Nested fragments disappear during transition animation

后端 未结 16 1709
广开言路
广开言路 2020-11-29 15:50

Here\'s the scenario: Activity contains fragment A, which in turn uses getChildFragmentManager() to add fragments A1 and A2

相关标签:
16条回答
  • 2020-11-29 16:23

    To animate dissapearance of neasted fragments we can force pop back stack on ChildFragmentManager. This will fire transition animation. To do this we need to catch up OnBackButtonPressed event or listen for backstack changes.

    Here is example with code.

    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 讨论(0)
  • 2020-11-29 16:24

    I think i found a better solution to this problem than snapshotting the current fragment to a bitmap as Luksprog suggested.

    The trick is to hide the fragment being removed or detached and only after the animations have been completed the fragment is removed or detached in its own fragment transaction.

    Imagine we have FragmentA and FragmentB, both with sub fragments. Now when you would normally do:

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

    Instead you do

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

    Now for the implementation of the Fragment:

    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();
        }
    }
    
    0 讨论(0)
  • 2020-11-29 16:27

    From the above answer of @kcoppock,

    if you have Activity->Fragment->Fragments ( multiple stacking, the following helps ), a minor edit to the best answer IMHO.

    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 讨论(0)
  • 2020-11-29 16:31

    The issue is fixed in androidx.fragment:fragment:1.2.0-alpha02. See https://issuetracker.google.com/issues/116675313 for more details.

    0 讨论(0)
提交回复
热议问题