FragmentTransaction animation to slide in over top

前端 未结 9 1370
星月不相逢
星月不相逢 2020-11-30 20:26

I am trying to achieve the following effect using FragmentTransaction.setCustomAnimations.

  1. Fragment A is showing
  2. Replace Fragment A with Fragment B. F
9条回答
  •  抹茶落季
    2020-11-30 20:53

    Based on jfrite answer attaching my implementations

    import android.content.res.Resources;
    import android.support.annotation.NonNull;
    import android.support.annotation.Nullable;
    import android.support.v4.app.Fragment;
    import android.support.v4.view.ViewCompat;
    import android.view.animation.Animation;
    import android.view.animation.AnimationUtils;
    import android.util.Log;
    
    public final class AnimationHelper {
        private AnimationHelper() {
    
        }
    
        private static String TAG = AnimationHelper.class.getSimpleName();
        private static final float ELEVATION_WHILE_ENTER_ANIMATION_IS_RUNNING = 100f;
        private static final int RESTORE_ANIMATION_DELAY = 16;
    
        /**
         * When replacing fragments with animations, by default the new fragment is placed below the replaced fragment. This
         * method returns an animation object that sets high elevation at the beginning of the animation and resets the
         * elevation when the animation completes. The {@link Animation} object that is returned is not the actual object
         * that is used for the animating the fragment but the callbacks are called at the appropriate time. The method
         * {@link Fragment#onCreateAnimation(int, boolean, int)} by default returns null, therefor, this method can be used
         * as the return value for {@link Fragment#onCreateAnimation(int, boolean, int)} method although it can return
         * null.
         * @param enter True if fragment is 'entering'.
         * @param nextAnim Animation resource id that is about to play.
         * @param fragment The animated fragment.
         * @return If nextAnim is a valid resource id and 'enter' is true, returns an {@link Animation} object with the
         * described above behavior, otherwise returns null.
         */
        @Nullable
        public static Animation increaseElevationWhileAnimating(boolean enter, int nextAnim,
                                                                @NonNull Fragment fragment) {
            if (!enter || nextAnim == 0) {
                return null;
            }
            Animation nextAnimation;
            try {
                nextAnimation = AnimationUtils.loadAnimation(fragment.getContext(), nextAnim);
            } catch (Resources.NotFoundException e) {
                Log.e(TAG, "Can't find animation resource", e);
                return null;
            }
            nextAnimation.setAnimationListener(new Animation.AnimationListener() {
                private float oldTranslationZ;
    
                @Override
                public void onAnimationStart(Animation animation) {
                    if (fragment.getView() != null && !fragment.isDetached()) {
                        oldTranslationZ = ViewCompat.getTranslationZ(fragment.getView());
                        ViewCompat.setTranslationZ(fragment.getView(), ELEVATION_WHILE_ENTER_ANIMATION_IS_RUNNING);
                    }
                }
    
                @Override
                public void onAnimationEnd(Animation animation) {
                    if (fragment.getView() != null && !fragment.isDetached()) {
                        fragment.getView().postDelayed(() -> {
                            // Decreasing the elevation at the ned can cause some flickering because of timing issues,
                            // Meaning that the replaced fragment did not complete yet the animation. Resting the animation
                            // with a minor delay solves the problem.
                            if (!fragment.isDetached()) {
                                ViewCompat.setTranslationZ(fragment.getView(), oldTranslationZ);
                            }
                        }, RESTORE_ANIMATION_DELAY);
                    }
                }
    
                @Override
                public void onAnimationRepeat(Animation animation) {
                }
            });
            return nextAnimation;
        }
    }
    

    Here is how I use the helper form the fragment.

    @Override
        public Animation onCreateAnimation(int transit, final boolean enter, int nextAnim) {
            return AnimationHelper.increaseElevationWhileAnimating(enter, nextAnim, this);
        }
    

    Here is how i start the fragment with animation

    FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
            ft.setCustomAnimations(R.anim.slide_in, R.anim.hold, R.anim.hold, R.anim.slide_out);
    

提交回复
热议问题