Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fragment customAnimation not working in Lollipop

I have below code for setting enter and exit animations for fragments.

final FragmentManager manager = getSupportFragmentManager();
final FragmentTransaction ft = manager.beginTransaction();
    ft.setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left, R.anim.slide_in_left, R.anim.slide_out_right);
    ft.replace(R.id.container, fragment, tag);
    ft.addToBackStack(tag);
    ft.commitAllowingStateLoss();

slide_in_left.xml

<?xml version="1.0" encoding="utf-8"?>

<set xmlns:android="http://schemas.android.com/apk/res/android">

    <translate android:fromXDelta="-100%"
    android:toXDelta="0%"
    android:duration="@integer/slide_anim_duration" />

</set>

Used same method for all other animations. Works fine in all other versions, but the problem is in Lollipop only. As we look in to the function
setCustomAnimations (int enter, int exit, int popEnter, int popExit) doc-link ,
enter and exit works fine, but popEnter and popExit fails in Lollipop.
Please guide me about what went wrong and provide a compatible solution that works from Android 2.3 to 5.1

Update:

Observing closely,it seems that the animation is there, but the duration has no effect.

like image 465
Nizam Avatar asked Apr 07 '15 09:04

Nizam


2 Answers

Fragment animations are broken even before L - there are some issues when changing screen orientation.

Below solution fixes both L issues and earlier orientation change issues. Use it as your base Fragment class.

public abstract class AnimatedSupportFragment extends DaggerFragment {

    private static final String STATE_ENTER_ANIM = "STATE_ENTER_ANIM";
    private static final String STATE_EXIT_ANIM = "STATE_EXIT_ANIM";
    private static final String STATE_POP_ENTER_ANIM = "STATE_POP_ENTER_ANIM";
    private static final String STATE_POP_EXIT_ANIM = "STATE_POP_EXIT_ANIM";
    private static final String STATE_CHANGING_CONFIGURATIONS = "STATE_CHANGING_CONFIGURATIONS";

    private @AnimRes int mEnter = 0;
    private @AnimRes int mExit = 0;
    private @AnimRes int mPopEnter = 0;
    private @AnimRes int mPopExit = 0;
    private boolean mIsChangingConfigurations = false;

    public void setCustomAnimations(@AnimRes int enterAnim,
                                    @AnimRes int exitAnim,
                                    @AnimRes int popEnterAnim,
                                    @AnimRes int popExitAnim) {
        mEnter = enterAnim;
        mExit = exitAnim;
        mPopEnter = popEnterAnim;
        mPopExit = popExitAnim;
    }

    @Override public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (savedInstanceState != null) {
            mEnter = savedInstanceState.getInt(STATE_ENTER_ANIM);
            mExit = savedInstanceState.getInt(STATE_EXIT_ANIM);
            mPopEnter = savedInstanceState.getInt(STATE_POP_ENTER_ANIM);
            mPopExit = savedInstanceState.getInt(STATE_POP_EXIT_ANIM);
            mIsChangingConfigurations = savedInstanceState.getBoolean(STATE_CHANGING_CONFIGURATIONS);
        }
    }

    @Override public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putInt(STATE_ENTER_ANIM, mEnter);
        outState.putInt(STATE_EXIT_ANIM, mExit);
        outState.putInt(STATE_POP_ENTER_ANIM, mPopEnter);
        outState.putInt(STATE_POP_EXIT_ANIM, mPopExit);
        outState.putBoolean(STATE_CHANGING_CONFIGURATIONS, mIsChangingConfigurations);
    }

    @Override public void onResume() {
        super.onResume();
        mIsChangingConfigurations = false;
    }

    @Override public void onPause() {
        super.onPause();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            mIsChangingConfigurations = getActivity().isChangingConfigurations();
        }
    }

    @SuppressLint("NewApi")
    @Override public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) {

        // This implementation fixes loosing transition animations on orientation changes:
        // @see http://stackoverflow.com/questions/8837408/fragment-lost-transition-animation-after-configuration-change
        // @see https://code.google.com/p/android/issues/detail?id=25994&can=4&colspec=ID%20Type%20Status%20Owner%20Summary%20Stars

        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
            // Do not support animations PRE-3.0, isChangingConfigurations() is not available!
            return null;
        }

        try {
            int anim;
            if (mIsChangingConfigurations) {
                // Recreating after change configuration, we don't want to play animation
                anim = 0;
            } else if (nextAnim != 0) {
                // Animation available (not lost) -> play it!
                anim = nextAnim;
            } else {
                // Animation probably lost - load anim saved in fragment state.
                // enter = we're about to play popEnterAnim, in other case popExitAnimation
                anim = enter ? mPopEnter : mPopExit;
            }
            if (anim != 0) {
                return AnimationUtils.loadAnimation(getActivity(), anim);
            }
        } catch (Exception ignore) {}

        return null;
    }
}
like image 143
jskierbi Avatar answered Nov 10 '22 08:11

jskierbi


you can additionally try onCreateAnimator in all the fragments..or the base fragment that they are extending...

@target_api 20 or higher

@Override
    public Animator onCreateAnimator(int transit, boolean enter, int nextAnim) {
        if (enter) {
            return AnimatorInflater.loadAnimator(getActivity(), R.animator.slide_in_top);
        } else {
            return AnimatorInflater.loadAnimator(getActivity(), R.animator.fade_out);
        }
    }

Note both above animators are pre defined and R there is android.R

Hope this helps cheers!

like image 35
Jivraj S Shekhawat Avatar answered Nov 10 '22 08:11

Jivraj S Shekhawat