Performing action after fragment transaction animation is finished

AndroidAndroid FragmentsAndroid Animation

Android Problem Overview


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?

Android Solutions


Solution 1 - Android

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;
    }
}

Solution 2 - Android

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;
   }    

Solution 3 - Android

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();
	
}

}

Solution 4 - Android

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);

Solution 5 - Android

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:

  • The parent fragment has to implement Animation.IAnimationListener
  • You have to return an AnimationSet otherwise the FragmentManager will override your listener and the callbacks won't fire.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMoopView Question on Stackoverflow
Solution 1 - AndroidmjamaView Answer on Stackoverflow
Solution 2 - AndroidnmwView Answer on Stackoverflow
Solution 3 - AndroidMeanmanView Answer on Stackoverflow
Solution 4 - AndroidGiuseppe SarnoView Answer on Stackoverflow
Solution 5 - AndroidpnavkView Answer on Stackoverflow