İç içe geçmiş parçalar, geçiş animasyonu sırasında kaybolur


99

İşte senaryo: Etkinlik parçasını içerir Adönüş kullanımlarında, getChildFragmentManager()parçaları eklemek A1ve A2de onun onCreateşöyle:

getChildFragmentManager()
  .beginTransaction()
  .replace(R.id.fragmentOneHolder, new FragmentA1())
  .replace(R.id.fragmentTwoHolder, new FragmentA2())
  .commit()

Şimdiye kadar çok iyi, her şey beklendiği gibi çalışıyor.

Daha sonra Activity'de aşağıdaki işlemi gerçekleştiririz:

getSupportFragmentManager()
  .beginTransaction()
  .setCustomAnimations(anim1, anim2, anim1, anim2)
  .replace(R.id.fragmentHolder, new FragmentB())
  .addToBackStack(null)
  .commit()

Geçiş sırasında, enterparçanın animasyonları Bdüzgün çalışır ancak A1 ve A2 parçaları tamamen kaybolur . Geri butonu ile işlemi geri aldığımızda, düzgün bir şekilde başlatılıyor ve popEnteranimasyon sırasında normal şekilde görüntüleniyor .

Kısa testimde daha tuhaflaştı - alt parçalar için animasyonları ayarlarsam (aşağıya bakın), exitparça eklediğimizde animasyon aralıklı olarak çalışırB

getChildFragmentManager()
  .beginTransaction()
  .setCustomAnimations(enter, exit)
  .replace(R.id.fragmentOneHolder, new FragmentA1())
  .replace(R.id.fragmentTwoHolder, new FragmentA2())
  .commit()

Elde etmek istediğim efekt basit - Parçadaki (anim2) animasyonun çalıştırılmasını exit(veya olması gerekir popExitmi?), AYuvalanmış alt öğeleri de dahil olmak üzere tüm kapsayıcıya animasyon uygulanmasını istiyorum.

Bunu başarmanın bir yolu var mı?

Düzenleme : Lütfen burada bir test senaryosu bulun

Edit2 : @StevenByle'a statik animasyonları denemeye devam etmem için beni zorladığı için teşekkürler. Görünüşe göre animasyonları işlem başına (tüm işlem için küresel değil) ayarlayabilirsiniz, bu da çocukların sonsuz bir statik animasyon setine sahip olabileceği, ebeveynlerinin farklı bir animasyona sahip olabileceği ve her şeyin tek bir işlemde gerçekleştirilebileceği anlamına gelir. . Aşağıdaki tartışmaya ve güncellenmiş test senaryosu projesine bakın .


Nedir R.id.fragmentHoldervs A, A1, A2, göre?
CommonsWare

fragmentHolder, aktivitenin düzeninde bir kimliktir, parça {Bir, İki} Tutucu, parça A'nın düzenindedir. Üçü de farklı. Fragment A başlangıçta fragmentHolder'a eklenmiştir (yani, fragman B, fragman A'nın yerini almaktadır).
Delyan

Burada örnek bir proje oluşturdum: github.com/BurntBrunch/NestedFragmentsAnimationsTest , ayrıca depoda bir apk de var. Bu gerçekten can sıkıcı bir hata ve bu sorunu çözmenin bir yolunu arıyorum (kodumda olmadığını varsayarak).
Delyan

Şimdi bu konu hakkında biraz daha fazla şey biliyorum. Parçaların kaybolmasının nedeni, çocukların yaşam döngüsü olaylarını ebeveynden önce işlemesidir. Temelde A1 ve A2, A'dan önce kaldırılır ve set animasyonları olmadığından aniden kaybolurlar. Bunu biraz hafifletmenin bir yolu, A'nın yerini alan işlemdeki A1 ve A2'yi açıkça kaldırmaktır. Bu şekilde, çıktıklarında canlandırırlar, ancak ana konteyner de animasyon yaptığı için animasyon hızlarının karesi alınır. Bu eseri üretmeyen bir çözüm takdir edilecektir.
Delyan

Soruda bahsettiğiniz değişiklik (başlangıç ​​parçasını değiştirmek) yapmak istediğiniz gerçek değişiklik mi yoksa sadece bir örnek mi? changeFragmentYöntemi yalnızca bir kez mi arayacaksınız ?
Luksprog

Yanıtlar:


37

Bir işlemde üst parça çıkarıldığında / değiştirildiğinde kullanıcının iç içe geçmiş parçaların kaybolduğunu görmesini önlemek için, bu parçaların ekranda göründükleri gibi bir görüntüsünü sağlayarak hala mevcut olan parçaların "simülasyonunu" yapabilirsiniz. Bu görüntü, iç içe geçmiş parça kapsayıcısı için bir arka plan olarak kullanılacaktır, böylece iç içe geçmiş parçanın görünümleri uzaklaşsa bile, görüntü bunların varlığını simüle edecektir. Ayrıca, iç içe geçmiş parçanın görüşleri ile etkileşimi kaybetmeyi bir sorun olarak görmüyorum çünkü kullanıcının sadece kaldırılma sürecindeyken (muhtemelen bir kullanıcı eylemi olarak iyi).

Arka plan görüntüsünü ayarlamakla ilgili küçük bir örnek yaptım (temel bir şey).


1
Size ödül vermeye karar verdim, çünkü sonunda kullandığım çözüm buydu. Zaman ayırdığınız için çok teşekkür ederim!
Delyan

17
Vay canına, çok pis. Biz Android geliştiricilerinin biraz becerikli olmak için gitmesi gereken uzunluklar
Dean Wild

1
i İkinci sekmeden bir Viewpager var, diğer parçayı değiştiriyorum ve üzerine bastığımda viewpager ikinci sekmesini göstermem gerekiyor, açılıyor ama boş sayfa gösteriyor. Yukarıdaki başlıkta önerdiğiniz şeyi denedim ama yine de aynı.
Harish

@Harish'in yazdığı gibi kullanıcı geri geldiğinde sorun devam ediyor
Ewoks

1
Cidden Vay canına? onun 2018 ve bu hala bir şey mi? :(
Archie G. Quiñones

69

Bu yüzden bunun için pek çok farklı geçici çözüm var gibi görünüyor, ancak @ Jayd16'nın cevabına dayanarak, alt parçalarda özel geçiş animasyonlarına hala izin veren ve yapmayı gerektirmeyen oldukça sağlam bir tümünü yakalama çözümü bulduğumu düşünüyorum. Düzenin bir bitmap önbelleği.

Genişleyen bir BaseFragmentsınıfa sahip olun Fragmentve tüm parçalarınızın bu sınıfı genişletmesini sağlayın (sadece alt parçalar değil).

Bu BaseFragmentsınıfa aşağıdakileri ekleyin:

// Arbitrary value; set it to some reasonable default
private static final int DEFAULT_CHILD_ANIMATION_DURATION = 250;

@Override
public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) {
    final Fragment parent = getParentFragment();

    // Apply the workaround only if this is a child fragment, and the parent
    // is being removed.
    if (!enter && parent != null && parent.isRemoving()) {
        // This is a workaround for the bug where child fragments disappear when
        // the parent is removed (as all children are first removed from the parent)
        // See https://code.google.com/p/android/issues/detail?id=55228
        Animation doNothingAnim = new AlphaAnimation(1, 1);
        doNothingAnim.setDuration(getNextAnimationDuration(parent, DEFAULT_CHILD_ANIMATION_DURATION));
        return doNothingAnim;
    } else {
        return super.onCreateAnimation(transit, enter, nextAnim);
    }
}

private static long getNextAnimationDuration(Fragment fragment, long defValue) {
    try {
        // Attempt to get the resource ID of the next animation that
        // will be applied to the given fragment.
        Field nextAnimField = Fragment.class.getDeclaredField("mNextAnim");
        nextAnimField.setAccessible(true);
        int nextAnimResource = nextAnimField.getInt(fragment);
        Animation nextAnim = AnimationUtils.loadAnimation(fragment.getActivity(), nextAnimResource);

        // ...and if it can be loaded, return that animation's duration
        return (nextAnim == null) ? defValue : nextAnim.getDuration();
    } catch (NoSuchFieldException|IllegalAccessException|Resources.NotFoundException ex) {
        Log.w(TAG, "Unable to load next animation from parent.", ex);
        return defValue;
    }
}

Ne yazık ki derinlemesine düşünme gerektiriyor; ancak, bu geçici çözüm destek kitaplığı için olduğundan, destek kitaplığınızı güncellemediğiniz sürece temeldeki uygulamanın değişme riskini taşımazsınız. Destek kitaplığını kaynaktan oluşturuyorsanız, bir sonraki animasyon kaynağı kimliği için bir erişimci ekleyebilir Fragment.javave yansıtma ihtiyacını ortadan kaldırabilirsiniz.

Bu çözüm, üst öğenin animasyon süresini "tahmin etme" ihtiyacını ortadan kaldırır (böylece "hiçbir şey yapma" animasyonu, ebeveynin çıkış animasyonuyla aynı süreye sahip olur) ve alt parçalarda özel animasyonlar yapmaya devam etmenize izin verir (örn. alt parçaların farklı animasyonlarla yeniden takas edilmesi).


5
Bu, iş parçacığındaki en sevdiğim çözüm. Bir bit eşlem gerektirmez, alt parçada fazladan kod gerektirmez ve üst kısımdan alt parçaya gerçekten bilgi sızdırmaz.
jacobhyphenated

1
@EugenPechanec Ana parçadan nextAnim'e ihtiyacınız var - çocuktan değil. Bütün mesele bu.
Kevin Coppock

1
Ne yazık ki bu yaklaşım, alt parçalar için ve dolaylı olarak ana parça için ve ayrıca Lollipop'un altındaki android sürümlerinde bir bellek sızıntısına neden oluyor :(
Cosmin

8
Bu çok kullanışlı çözüm için teşekkürler, ancak mevcut destek kitaplığıyla çalışmak için küçük bir güncelleme gerekiyor (27.0.2, hangi sürümün bu kodu kırdığını bilmiyorum). mNextAnimartık bir mAnimationInfonesnenin içindedir . Buna şu şekilde erişebilirsiniz:Field animInfoField = Fragment.class.getDeclaredField("mAnimationInfo"); animInfoField.setAccessible(true); Object animationInfo = animInfoField.get(fragment); Field nextAnimField = animationInfo.getClass().getDeclaredField("mNextAnim");
David Lericolais

5
@DavidLericolais, sizinkinden sonra başka bir kod satırı eklemek istiyor. val nextAnimResource = nextAnimField.getInt(animationInfo);hattı değiştirmek içinint nextAnimResource = nextAnimField.getInt(fragment);
tingyik90

32

Oldukça temiz bir çözüm bulabildim. IMO en az hack'lidir ve teknik olarak "bir bitmap çiz" çözümü olsa da, en azından lib parçası tarafından soyutlanmıştır.

Çocuk parçalarının şununla bir ana sınıfı geçersiz kıldığından emin olun:

private static final Animation dummyAnimation = new AlphaAnimation(1,1);
static{
    dummyAnimation.setDuration(500);
}

@Override
public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) {
    if(!enter && getParentFragment() != null){
        return dummyAnimation;
    }
    return super.onCreateAnimation(transit, enter, nextAnim);
}

Alt parçalarda bir çıkış animasyonumuz varsa, yanıp sönmek yerine bunlar animasyonlu olacaktır. Bir süre boyunca alt parçalarını tam alfa ile basitçe çizen bir animasyona sahip olarak bundan faydalanabiliriz. Bu şekilde, canlandırılırken ana parçada görünür kalarak istenen davranışı verirler.

Aklıma gelen tek konu, bu süreyi takip etmek. Belki büyük bir sayıya ayarlayabilirim ama korkarım bu animasyonu bir yere çiziyorsa performans sorunları olabilir.


Yardımcı olur, teşekkürler. Süre süresinin değeri önemli değil
iscariot

şimdiye kadarki en temiz çözüm
Liran Cohen

16

Çözümümü netlik için gönderiyorum. Çözüm oldukça basit. Üst öğenin parça işlem animasyonunu taklit etmeye çalışıyorsanız, yalnızca aynı süreye sahip alt parça işlemine özel bir animasyon ekleyin. Oh ve add () 'dan önce özel animasyonu ayarladığınızdan emin olun.

getChildFragmentManager().beginTransaction()
        .setCustomAnimations(R.anim.none, R.anim.none, R.anim.none, R.anim.none)
        .add(R.id.container, nestedFragment)
        .commit();

R.anim.none için xml (Ebeveynlerimin animasyon giriş / çıkış süresi 250ms'dir)

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate android:fromXDelta="0" android:toXDelta="0" android:duration="250" />
</set>

Çok benzer bir şey yaptım ama çocuğu güncellerken "ekle" yerine "göster" kullandım. Ayrıca "getChildFragmentManager (). ExecutePendingTransactions ()" ekledim, ancak bunun kesinlikle gerekli olup olmadığından emin değilim. Yine de bu çözüm gayet iyi çalışıyor ve bazılarının önerdiği gibi Parçanın "bir görüntüsünü sağlamayı" gerektirmiyor.
Brian Yencho

Bu harikaydı. Ancak, çocuğumun parçalarını değiştirirken gecikme yaşıyordum. bundan kaçınmak için 2. parametreyi animasyonsuz olarak ayarlayın:fragmentTransaction.setCustomAnimations(R.anim.none, 0, R.anim.none, R.anim.none)
ono

7

Bunun probleminizi tam olarak çözemeyebileceğini anlıyorum, ama belki başkasının ihtiyaçlarına uyacaktır, çocuklarınızın aslında hareket etmeyen / hareketlendirmeyen enter/ exitve popEnter/ popExitanimasyonları ekleyebilirsiniz . Animasyonlar, ana animasyonlarıyla aynı süreye / kaymaya sahip olduğu sürece, ebeveynin animasyonuyla hareket ediyor / hareket ediyor gibi görünecekler.FragmentFragmentFragment


1
Çözümü evrensel olarak işe yaradığı için ödülü Luksprog'a verdim. Statik animasyonlar hilesini denedim (süresi aslında önemli değil - ebeveyn gittiğinde, görüşler açıkça kaybolur) ancak olası tüm durumlarda işe yaramadı (sorunun altındaki yorumlarıma bakın). Ayrıca, çocuklu bir parçanın ebeveyninin bu gerçeği bilmesi ve çocukların animasyonlarını oluşturmak için fazladan adımlar atması gerektiğinden, bu yaklaşım soyutlamayı sızdırır. Her durumda, zaman ayırdığınız için çok teşekkür ederim!
Delyan

Kabul edildi, bu, su geçirmez bir çözümden çok bir geçici çözümdür ve biraz kırılgan olarak kabul edilebilir. Ancak basit durumlarda işe yarayacaktır.
Steven Byle

4

bunu çocuk fragmanında yapabilirsiniz.

@Override
public Animator onCreateAnimator(int transit, boolean enter, int nextAnim) {
    if (true) {//condition
        ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(getView(), "alpha", 1, 1);
        objectAnimator.setDuration(333);//time same with parent fragment's animation
        return objectAnimator;
    }
    return super.onCreateAnimator(transit, enter, nextAnim);
}

Teşekkür ederim! Belki en iyisi değil ama muhtemelen en basit çözüm.
bug56

2

@@@@@@@@@@@@@@@@@@@@@@@@@@@

DÜZENLEME: Sahip olduğu başka sorunlar olduğu için bu çözümü uygulamadan bıraktım. Square, kısa süre önce parçaların yerini alan 2 kitaplıkla çıktı. Bunun aslında Google'ın yapmalarını istemediği bir şeyi yapmak için parçaları kırmaya çalışmaktan daha iyi bir alternatif olabileceğini söyleyebilirim.

http://corner.squareup.com/2014/01/mortar-and-flow.html

@@@@@@@@@@@@@@@@@@@@@@@@@@@

Gelecekte bu sorunu yaşayan insanlara yardım etmek için bu çözümü ortaya koyacağımı düşündüm. Başkalarıyla yapılan orijinal poster sohbetlerinin izini sürer ve gönderdiği koda bakarsanız, orijinal posterin sonunda ana parçayı canlandırırken alt parçalarda işlemsiz bir animasyon kullanma sonucuna vardığını görürsünüz. Bu çözüm, sizi FragmentPagerAdapter ile bir ViewPager kullanırken külfetli olabilecek tüm alt parçaların kaydını tutmaya zorladığından ideal değildir.

Her yerde Alt Parçalar kullandığım için verimli ve modüler (yani kolayca çıkarılabilen) bu çözümü buldum ve düzeltmeleri durumunda ve bu işlemsiz animasyona artık ihtiyaç kalmadı.

Bunu gerçekleştirmenin birçok yolu var. Bir singleton kullanmayı seçtim ve ona ChildFragmentAnimationManager diyorum. Temel olarak benim için ebeveynine bağlı olarak bir çocuk parçasını takip edecek ve istendiğinde çocuklara işlemsiz bir animasyon uygulayacak.

public class ChildFragmentAnimationManager {

private static ChildFragmentAnimationManager instance = null;

private Map<Fragment, List<Fragment>> fragmentMap;

private ChildFragmentAnimationManager() {
    fragmentMap = new HashMap<Fragment, List<Fragment>>();
}

public static ChildFragmentAnimationManager instance() {
    if (instance == null) {
        instance = new ChildFragmentAnimationManager();
    }
    return instance;
}

public FragmentTransaction animate(FragmentTransaction ft, Fragment parent) {
    List<Fragment> children = getChildren(parent);

    ft.setCustomAnimations(R.anim.no_anim, R.anim.no_anim, R.anim.no_anim, R.anim.no_anim);
    for (Fragment child : children) {
        ft.remove(child);
    }

    return ft;
}

public void putChild(Fragment parent, Fragment child) {
    List<Fragment> children = getChildren(parent);
    children.add(child);
}

public void removeChild(Fragment parent, Fragment child) {
    List<Fragment> children = getChildren(parent);
    children.remove(child);
}

private List<Fragment> getChildren(Fragment parent) {
    List<Fragment> children;

    if ( fragmentMap.containsKey(parent) ) {
        children = fragmentMap.get(parent);
    } else {
        children = new ArrayList<Fragment>(3);
        fragmentMap.put(parent, children);
    }

    return children;
}

}

Daha sonra, Parçayı genişleten bir sınıfa sahip olmanız gerekir (en azından Alt Parçalarınız). Bu sınıfa zaten sahiptim ve ona BaseFragment diyorum. Bir parça görünümü oluşturulduğunda, onu ChildFragmentAnimationManager'a ekleriz ve yok edildiğinde kaldırırız. Bunu, Eklenti / Ayırma veya dizideki diğer eşleştirme yöntemlerinde yapabilirsiniz. Görünüm Oluşturma / Yok Etme'yi seçme mantığım, bir Parçanın Görünümü yoksa, görülmeye devam etmesi için onu canlandırmayı umursamıyorum. Bu yaklaşım, Fragment kullanan ViewPager'larla da daha iyi çalışmalıdır çünkü bir FragmentPagerAdapter'ın tuttuğu her bir Fragmanı takip etmeyeceksiniz, sadece 3.

public abstract class BaseFragment extends Fragment {

@Override
public  View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {

    Fragment parent = getParentFragment();
    if (parent != null) {
        ChildFragmentAnimationManager.instance().putChild(parent, this);
    }

    return super.onCreateView(inflater, container, savedInstanceState);
}

@Override
public void onDestroyView() {
    Fragment parent = getParentFragment();
    if (parent != null) {
        ChildFragmentAnimationManager.instance().removeChild(parent, this);
    }

    super.onDestroyView();
}

}

Artık tüm Parçalarınız ana parça tarafından bellekte saklandığına göre, onlara bu şekilde canlandırma diyebilirsiniz ve alt parçalarınız kaybolmaz.

FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();
ChildFragmentAnimationManager.instance().animate(ft, ReaderFragment.this)
                    .setCustomAnimations(R.anim.up_in, R.anim.up_out, R.anim.down_in, R.anim.down_out)
                    .replace(R.id.container, f)
                    .addToBackStack(null)
                    .commit();

Ayrıca, elinizde olması için, res / anim klasörünüze giden no_anim.xml dosyası:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@android:anim/linear_interpolator">
    <translate android:fromXDelta="0" android:toXDelta="0"
        android:duration="1000" />
</set>

Yine, bu çözümün mükemmel olduğunu düşünmüyorum, ancak her bir çocuğu takip etmek için ana parçada özel kod uygulayan bir Çocuk Parçasına sahip olduğunuz her durumdan çok daha iyidir. Ben oradaydım ve bu hiç eğlenceli değil.


1

Luksprog'un önerdiği gibi, mevcut parçayı bir bit eşlemde anlık görüntülemekten daha iyi bir çözüm bulduğumu düşünüyorum.

İşin püf noktası, kaldırılan veya ayrılan parçayı gizlemektir ve yalnızca animasyonlar tamamlandıktan sonra, parça kendi parça işleminde kaldırılır veya ayrılır.

Elimizdeki düşünün FragmentAve FragmentBher iki alt parçalarıyla. Şimdi normalde yapacağınız zaman:

getSupportFragmentManager()
  .beginTransaction()
  .setCustomAnimations(anim1, anim2, anim1, anim2)
  .add(R.id.fragmentHolder, new FragmentB())
  .remove(fragmentA)    <-------------------------------------------
  .addToBackStack(null)
  .commit()

Onun yerine yaparsın

getSupportFragmentManager()
  .beginTransaction()
  .setCustomAnimations(anim1, anim2, anim1, anim2)
  .add(R.id.fragmentHolder, new FragmentB())
  .hide(fragmentA)    <---------------------------------------------
  .addToBackStack(null)
  .commit()

fragmentA.removeMe = true;

Şimdi Fragmanın uygulanması için:

public class BaseFragment extends Fragment {

    protected Boolean detachMe = false;
    protected Boolean removeMe = false;

    @Override
    public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) {
        if (nextAnim == 0) {
            if (!enter) {
                onExit();
            }

            return null;
        }

        Animation animation = AnimationUtils.loadAnimation(getActivity(), nextAnim);
        assert animation != null;

        if (!enter) {
            animation.setAnimationListener(new Animation.AnimationListener() {
                @Override
                public void onAnimationStart(Animation animation) {
                }

                @Override
                public void onAnimationEnd(Animation animation) {
                    onExit();
                }

                @Override
                public void onAnimationRepeat(Animation animation) {
                }
            });
        }

        return animation;
    }

    private void onExit() {
        if (!detachMe && !removeMe) {
            return;
        }

        FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
        if (detachMe) {
            fragmentTransaction.detach(this);
            detachMe = false;
        } else if (removeMe) {
            fragmentTransaction.remove(this);
            removeMe = false;
        }
        fragmentTransaction.commit();
    }
}

PopBackStack, ayrılmış bir Parçayı göstermeye çalıştığı için bir Hataya neden olmaz mı?
Alexandre

1

Harita parçasıyla aynı sorunu yaşıyordum. İçerdiği parçanın çıkış animasyonu sırasında kaybolmaya devam etti. Çözüm, alt harita parçası için, ana parçanın çıkış animasyonu sırasında görünür kalmasını sağlayacak animasyon eklemektir. Alt parçanın animasyonu, süresi boyunca alfasını% 100'de tutuyor.

Animasyon: res / animator / keep_child_fragment.xml

<?xml version="1.0" encoding="utf-8"?>    
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <objectAnimator
        android:propertyName="alpha"
        android:valueFrom="1.0"
        android:valueTo="1.0"
        android:duration="@integer/keep_child_fragment_animation_duration" />
</set>

Animasyon, daha sonra harita parçası ana parçaya eklendiğinde uygulanır.

Üst parça

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {

    View view = inflater.inflate(R.layout.map_parent_fragment, container, false);

    MapFragment mapFragment =  MapFragment.newInstance();

    getChildFragmentManager().beginTransaction()
            .setCustomAnimations(R.animator.keep_child_fragment, 0, 0, 0)
            .add(R.id.map, mapFragment)
            .commit();

    return view;
}

Son olarak, alt parça animasyonunun süresi bir kaynak dosyasında ayarlanır.

değerler / integers.xml

<resources>
  <integer name="keep_child_fragment_animation_duration">500</integer>
</resources>

0

Temizlenmiş parçaların kaybolmasını canlandırmak için, ChildFragmentManager'da geri tepme yığınını zorlayabiliriz. Bu, geçiş animasyonunu ateşleyecektir. Bunu yapmak için OnBackButtonPressed olayını yakalamamız veya backstack değişikliklerini dinlememiz gerekir.

İşte kodlu örnek.

View.OnClickListener() {//this is from custom button but you can listen for back button pressed
            @Override
            public void onClick(View v) {
                getChildFragmentManager().popBackStack();
                //and here we can manage other fragment operations 
            }
        });

  Fragment fr = MyNeastedFragment.newInstance(product);

  getChildFragmentManager()
          .beginTransaction()
                .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_CLOSE)
                .replace(R.neasted_fragment_container, fr)
                .addToBackStack("Neasted Fragment")
                .commit();

0

Geçenlerde sorumda şu sorunla karşılaştım: İç içe geçmiş parçalar yanlış geçiş yapıyor

Bunu bir bitmap kaydetmeden, yansıma veya diğer tatmin edici olmayan yöntemler kullanmadan çözen bir çözümüm var.

Örnek bir proje burada görüntülenebilir: https://github.com/zafrani/NestedFragmentTransitions

Efektin bir GIF'i burada görüntülenebilir: https://imgur.com/94AvrW4

Örneğimde, iki ebeveyn parçası arasında bölünmüş 6 çocuk parçası var. Giriş, çıkış, pop ve push geçişlerini sorunsuz bir şekilde yapabiliyorum. Konfigürasyon değişiklikleri ve geri baskılar da başarıyla gerçekleştirilir.

Çözümün büyük kısmı, BaseFragment'ımın (çocuklarım ve üst parçalarım tarafından genişletilen parça) şuna benzeyen onCreateAnimator işlevinde:

   override fun onCreateAnimator(transit: Int, enter: Boolean, nextAnim: Int): Animator {
    if (isConfigChange) {
        resetStates()
        return nothingAnim()
    }

    if (parentFragment is ParentFragment) {
        if ((parentFragment as BaseFragment).isPopping) {
            return nothingAnim()
        }
    }

    if (parentFragment != null && parentFragment.isRemoving) {
        return nothingAnim()
    }

    if (enter) {
        if (isPopping) {
            resetStates()
            return pushAnim()
        }
        if (isSuppressing) {
            resetStates()
            return nothingAnim()
        }
        return enterAnim()
    }

    if (isPopping) {
        resetStates()
        return popAnim()
    }

    if (isSuppressing) {
        resetStates()
        return nothingAnim()
    }

    return exitAnim()
}

Etkinlik ve ana parça, bu boole'ların durumlarının ayarlanmasından sorumludur. Örnek projemden nasıl ve nerede olduğunu görmek daha kolay.

Örneğimde destek parçalarını kullanmıyorum, ancak aynı mantık onCreateAnimation işlevi ve onCreateAnimation işlevi ile kullanılabilir


0

Bu sorunu çözmenin basit bir yolu Fragment, standart kitaplık parçası sınıfı yerine bu kitaplıktaki sınıfı kullanmaktır:

https://github.com/marksalpeter/contract-fragment

Bir yan not olarak, pakette ayrıca ContractFragment, üst-alt parça ilişkisini kullanarak uygulamalarınızı oluşturmak için yararlı bulabileceğiniz yararlı bir temsilci modeli de bulunur .


0

@Kcoppock'un yukarıdaki cevabından,

Aktivite-> Parça-> Parçalarınız varsa (çoklu istifleme, aşağıdakiler yardımcı olur), en iyi yanıt IMHO için küçük bir düzenleme.

public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) {

    final Fragment parent = getParentFragment();

    Fragment parentOfParent = null;

    if( parent!=null ) {
        parentOfParent = parent.getParentFragment();
    }

    if( !enter && parent != null && parentOfParent!=null && parentOfParent.isRemoving()){
        Animation doNothingAnim = new AlphaAnimation(1, 1);
        doNothingAnim.setDuration(getNextAnimationDuration(parent, DEFAULT_CHILD_ANIMATION_DURATION));
        return doNothingAnim;
    } else
    if (!enter && parent != null && parent.isRemoving()) {
        // This is a workaround for the bug where child fragments disappear when
        // the parent is removed (as all children are first removed from the parent)
        // See https://code.google.com/p/android/issues/detail?id=55228
        Animation doNothingAnim = new AlphaAnimation(1, 1);
        doNothingAnim.setDuration(getNextAnimationDuration(parent, DEFAULT_CHILD_ANIMATION_DURATION));
        return doNothingAnim;
    } else {
        return super.onCreateAnimation(transit, enter, nextAnim);
    }
}

0

Benim sorunum ana parçanın kaldırılmasıyla ilgiliydi (ft.remove (fragment)), çocuk animasyonları gerçekleşmiyordu.

Temel sorun, alt parçaların, animasyondan çıkan üst öğe parçasından ÖNCE hemen YOK EDİLMESİ.

Alt parçaların özel animasyonları, Üst Parça kaldırıldığında yürütülmez

Başkalarının atlattığı gibi, EBEVEYN'in çıkarılmasından önce EBEVEYN'i (çocuğu değil) gizlemek gitmenin yoludur.

            val ft = fragmentManager?.beginTransaction()
            ft?.setCustomAnimations(R.anim.enter_from_right,
                    R.anim.exit_to_right)
            if (parentFragment.isHidden()) {
                ft?.show(vehicleModule)
            } else {
                ft?.hide(vehicleModule)
            }
            ft?.commit()

Ebeveyni gerçekten kaldırmak istiyorsanız, animasyonun ne zaman bittiğini bilmek için muhtemelen özel animasyonunuz için bir dinleyici ayarlamalısınız, böylece Ebeveyn Parçasında güvenli bir şekilde bazı sonlandırma yapabilirsiniz (kaldır). Bunu zamanında yapmazsanız animasyonu sonlandırabilirsiniz. NB animasyonu, kendi asenkron kuyruğunda yapılır.

BTW, ana animasyonları devralacakları için alt parçada özel animasyonlara ihtiyacınız yoktur.



0

Eski iş parçacığı, ama biri buraya rastlarsa diye:

Yukarıdaki yaklaşımların tümü benim için pek çekici gelmiyor, bitmap çözümü çok kirli ve performans göstermiyor; diğerleri alt parçaların, söz konusu alt parçayı yaratmak için kullanılan işlemde kullanılan geçişin süresi hakkında bilgi sahibi olmasını gerektirir. Gözlerimde daha iyi bir çözüm aşağıdakilere benzer bir şey:

val currentFragment = supportFragmentManager.findFragmentByTag(TAG)
val transaction = supportFragmentManager
    .beginTransaction()
    .setCustomAnimations(anim1, anim2, anim1, anim2)
    .add(R.id.fragmentHolder, FragmentB(), TAG)
if (currentFragment != null) {
    transaction.hide(currentFragment).commit()
    Handler().postDelayed({
        supportFragmentManager.beginTransaction().remove(currentFragment).commit()
    }, DURATION_OF_ANIM)
} else {
    transaction.commit()
}

Sadece mevcut parçayı gizleriz ve yeni parçayı ekleriz, animasyon bittiğinde eski parçayı kaldırırız. Bu şekilde tek bir yerde işlenir ve bit eşlem oluşturulmaz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.