Reputation: 5731
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.
Upvotes: 23
Views: 1773
Reputation: 16614
Here is the working solution: Modified version of @jskierbi answer.
import android.support.v4.app.Fragment;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
/**
* @author : [email protected] Created on: 2016-02-19
*/
public class SupportBaseFragment extends Fragment {
private boolean mIsChangingConfigurations = false;
private static final String STATE_CHANGING_CONFIGURATIONS = "STATE_CHANGING_CONFIGURATIONS";
@Override
public void onResume() {
super.onResume();
mIsChangingConfigurations = false;
}
@Override
public void onPause() {
super.onPause();
mIsChangingConfigurations = getActivity().isChangingConfigurations();
}
@Override
public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) {
if (mIsChangingConfigurations)
return null;
if (enter)
return AnimationUtils.loadAnimation(getContext(), nextAnim == 0 ? R.anim.enter_pop : nextAnim);
else
return AnimationUtils.loadAnimation(getContext(), nextAnim == 0 ? R.anim.exit_pop : nextAnim);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
mIsChangingConfigurations = savedInstanceState.getBoolean(STATE_CHANGING_CONFIGURATIONS);
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean(STATE_CHANGING_CONFIGURATIONS, mIsChangingConfigurations);
}
enter.xml
<?xml version="1.0" encoding="utf-8"?>
<set>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="@android:integer/config_mediumAnimTime"
android:fromXDelta="100%"
android:interpolator="@android:anim/decelerate_interpolator"
android:toXDelta="0"/>
</set>
enter_pop.xml
<?xml version="1.0" encoding="utf-8"?>
<set>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="@android:integer/config_mediumAnimTime"
android:fromXDelta="-100%"
android:interpolator="@android:anim/decelerate_interpolator"
android:toXDelta="0"/>
</set>
exit.xml
<?xml version="1.0" encoding="utf-8"?>
<set>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="@android:integer/config_mediumAnimTime"
android:fromXDelta="0"
android:interpolator="@android:anim/accelerate_interpolator"
android:toXDelta="-100%"/>
</set>
exit_pop.xml
<?xml version="1.0" encoding="utf-8"?>
<set>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="@android:integer/config_mediumAnimTime"
android:fromXDelta="0"
android:interpolator="@android:anim/accelerate_interpolator"
android:toXDelta="100%"/>
</set>
Usage:
getSupportFragmentManager()
.beginTransaction()
.setCustomAnimations(R.anim.enter, R.anim.exit,
R.anim.enter_pop, R.anim.exit_pop)
.replace(R.id.fragment_container, myFancyFragment)
.addToBackStack(null)
.commit();
Upvotes: 0
Reputation: 1042
I find an other solution, it not makes exactly the same animation, but is very similar, I like this animation more than the traditional slide this is my code for do the animation:
private Fragment fragment=new Fragment();
private FragmentManager fragmentManager=getSupportFragmentManager();
private void replaceFragmentWithAnimation(){
FragmentTransaction ft = fragmentManager.beginTransaction();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && fragment != null) {
Slide slideLeft = new Slide(Gravity.RIGHT);
slideLeft.setDuration(300);
fragment.setExitTransition(slideLeft);
}
fragment = CalendarFragment.newInstance(selectedDays, plusMonths);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Slide slideRight = new Slide(Gravity.RIGHT);
slideRight.setDuration(350);
fragment.setEnterTransition(slideRight);
} else {
ft.setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_right);
}
ft.replace(calendarDaysContFL.getId(), fragment);
ft.commit();
}
Upvotes: 0
Reputation: 1042
If you put the duration to 2000 you will see the animation, but I think it's too slow. This is my code:
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXDelta="-100%p"
android:toXDelta="0"
android:interpolator="@android:anim/decelerate_interpolator"
android:duration="2000" />
You can put less duration, but you will see less animation.
Upvotes: 0
Reputation: 1635
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;
}
}
Upvotes: 3
Reputation: 352
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!
Upvotes: 1