I want to set a buttons visibility after the animation is finished.
That's what calls the animation:
android.support.v4.app.FragmentTransaction fAnimation = this.getActivity().getSupportFragmentManager().beginTransaction();
fAnimation.setCustomAnimations(android.R.anim.slide_in_left, R.anim.pull_out_to_left);
if (this.isVisible()) {
fAnimation.hide(this);
fAnimation.commit();
}
// code that will be executed when the fragment is gone (after the animation is over)
Is there any way to attach a listener to know when my fragment is gone?
At a high level, here's how to make a fragment transition with shared elements: Assign a unique transition name to each shared element view. Add shared element views and transition names to the FragmentTransaction . Set a shared element transition animation.
To animate the transition between fragments, or to animate the process of showing or hiding a fragment you use the Fragment Manager to create a Fragment Transaction . Within each Fragment Transaction you can specify in and out animations that will be used for show and hide respectively (or both when replace is used).
To add a fragment to a FragmentManager , call add() on the transaction. This method receives the ID of the container for the fragment, as well as the class name of the fragment you wish to add. The added fragment is moved to the RESUMED state.
The Animators that @nmw implements in his answer were added in API Level 11 and will not work with Fragments as implemented by the Android support library.
To listen to Fragment animation events, I extended the support library's Fragment
class and overrode onCreateAnimation
, attaching a custom AnimationListener to the returned Animation object:
public class MyFragment extends android.support.v4.app.Fragment {
private static final String TAG = "MyFragment";
@Override
public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) {
Animation anim = AnimationUtils.loadAnimation(getActivity(), nextAnim);
anim.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
Log.d(TAG, "Animation started.");
// additional functionality
}
@Override
public void onAnimationRepeat(Animation animation) {
Log.d(TAG, "Animation repeating.");
// additional functionality
}
@Override
public void onAnimationEnd(Animation animation) {
Log.d(TAG, "Animation ended.");
// additional functionality
}
});
return anim;
}
}
You need to subclass Fragment and override onCreateAnimator, then you can load those animations from XML and attach listeners to them.
E.g.
public class MyFragment extends Fragment
{
@Override
public Animator onCreateAnimator(int transit, boolean enter, int nextAnim)
{
final int animatorId = (enter) ? R.anim.in_anim : R.anim.out_anim;
final Animator anim = AnimatorInflater.loadAnimator(getActivity(), animatorId);
anim.addListener(new AnimatorListenerAdapter()
{
@Override
public void onAnimationStart(Animator animation)
{
...
}
@Override
public void onAnimationEnd(Animator animation)
{
...
}
});
return anim;
}
Combining the answers above here is a sample I am using successfully with the support library fragments.
Simply extend the MenuFragment and set the listener to get a callback of what to execute afterwards.
public class MenuFragment extends Fragment {
private WeakReference<OnMenuClosedListener> onMenuClosedListener;
@Override
public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) {
Animation anim = null;
if (enter) {
anim = AnimationUtils.loadAnimation(getActivity(), R.anim.anim_slide_in_top);
} else {
anim = AnimationUtils.loadAnimation(getActivity(), R.anim.anim_menu_slide_out_top);
anim.setAnimationListener(new AnimationListener() {
@Override public void onAnimationStart(Animation animation) {
}
@Override public void onAnimationRepeat(Animation animation) {
}
@Override public void onAnimationEnd(Animation animation) {
onMenuClosed();
}
});
}
// NOTE: the animation must be added to an animation set in order for the listener
// to work on the exit animation
AnimationSet animSet = new AnimationSet(true);
animSet.addAnimation(anim);
return animSet;
}
private void onMenuClosed() {
if (this.onMenuClosedListener != null) {
OnMenuClosedListener listener = this.onMenuClosedListener.get();
if (listener != null) {
listener.onMenuClosed();
}
}
}
public void setOnMenuClosedListener(OnMenuClosedListener listener) {
this.onMenuClosedListener = new WeakReference<MenuFragment.OnMenuClosedListener>(listener);
}
/**
* Callback for when the menu is closed.
*/
public static interface OnMenuClosedListener {
public abstract void onMenuClosed();
}
}
Added in API 26 (and in Support Library) you can use
FragmentTransaction runOnCommit (Runnable runnable);
For example:
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.setCustomAnimations(R.anim.enter_from_right, R.anim.exit_from_left);
ft.show(YourFragment);
ft.commit();
ft.runOnCommit(() -> Your_Action_Here);
I had to do this in Xamarin. My situation was I needed a callback once the fragment animation ended. Here is how I made it work without any flickering (this is C#/Xamarin):
public override Animation OnCreateAnimation(int transit, bool enter, int nextAnim)
{
Animation anim = base.OnCreateAnimation(transit, enter, nextAnim);
if (anim == null && nextAnim != 0) {
anim = AnimationUtils.LoadAnimation(Activity, nextAnim);
}
anim.SetAnimationListener(this);
return anim;
}
public void OnAnimationEnd(Animation animation)
{
}
public void OnAnimationRepeat(Animation animation)
{
}
public void OnAnimationStart(Animation animation)
{
}
Note:
Animation.IAnimationListener
AnimationSet
otherwise the FragmentManager
will override your listener and the callbacks won't fire.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With