Pop fragment backstack without playing Pop-Animation

I click on a fragment on the fragment stack using the following code:

FragmentManager fragmentManager = getActivity().getSupportFragmentManager(); FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); fragmentTransaction.setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_right, R.anim.slide_in_left, R.anim.slide_out_left); fragmentTransaction.replace(getId(), newFragment); fragmentTransaction.addToBackStack(null); fragmentTransaction.commit(); 

Thus, when the stack of a fragment is pushed, for example. by pressing the "Back" button, the animation of the pop fragment is played. However, there are situations in which I would like to place a backstack fragment without showing this animation, for example. because I just returned from another action and want to display the previous fragment immediately, without animation.

An example navigation might look like this:

  • The user is on the start screen with the root fragment
  • He selects a root fragment element, which then displays a new fragment to display the details of that element. He does this using a fragment transaction, which sets the animation for both clicking and pop-flag (therefore, when the user clicks the back button, the transition is animated)
  • An action starts from this fragment, which (for some reason) deletes the object just shown
  • When this action completes, I would like to return to the root fragment without showing the “pop animation” of the detail fragment

Is there a way to pull out a fragment of a fragment without playing the specified pop animation?

+52
android android-fragments android-animation
Feb 08 2018-12-12T00:
source share
12 answers

So, Warpzit was on the right track, he was just not too well versed in your specific problem. I ran into the same problem, and this is how I solved it.

First I created a static boolean (for simplicity, put it in the FragmentUtils class) ...

 public class FragmentUtils { public static boolean sDisableFragmentAnimations = false; } 

Then, in any of the fragments, you must override the onCreateAnimation method ...

 @Override public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) { if (FragmentUtils.sDisableFragmentAnimations) { Animation a = new Animation() {}; a.setDuration(0); return a; } return super.onCreateAnimation(transit, enter, nextAnim); } 

Then, when you need to clear the backstack of your activity, simply follow these steps:

 public void clearBackStack() { FragmentUtils.sDisableFragmentAnimations = true; getSupportFragmentManager().popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE); FragmentUtils.sDisableFragmentAnimations = false; } 

And voila, calling clearBackStack () will bring you back to the root fragment without any transient animations.

Hopefully big G will add a less silly way to do this in the future.

+85
Jun 28 2018-12-12T00:
source share

So, for the support library, the following works:

In a snippet that should have custom pop animation, you override onCreateAnimation with your own. You can get it and set some parameter depending on what you want. You may need to do extra work to get it to work with regular snippets.

Here is an example where I redefine it and change the dialing duration:

 @Override public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) { Animation anim = (Animation) super.onCreateAnimation(transit, enter, nextAnim); if(!enter) { if(anim != null) { anim.setDuration(0); // This doesn't seem to be called. return anim; } else { Animation test = new TestAnimation(); test.setDuration(0); return test; } } return anim; } private class TestAnimation extends Animation { } 
+6
May 21 '12 at 9:37 a.m.
source share

The user is on the start screen with the root fragment

Suppose a root fragment is contained in Activity A.

He selects an element in the root fragment, which then displays a new fragment to show the details of that element. For this, a fragment transaction is used, which sets the animation for both push and pop-up window (therefore, when the user presses the back button, the transition is animated)

The transaction is added to the back stack. This means that when you click the Back button from a part fragment, the ascent process is animated.

From this fragment, he begins an action that (for some reason) deletes the element just shown.

Let's say this is activity B

When this action is finished, I would like to return to the root fragment without showing the "pop-up animation" of the "fragment of the part"

One way to get this behavior is to do this in exercise B:

 Intent intent = new Intent(this, A.class); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); finish(); 

This will start action A, resetting it to its root state according to the documentation (check the last paragraph in the section that says: “This launch mode can also be used to achieve a good effect in combination with FLAG_ACTIVITY_NEW_TASK: ......”)

With this configuration, the animation will be present in the default case, whereas in a special case you can control the animation using:

 intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); 

Which starts a new activity without animation. If you need animation, you can do this using the overridePendingTransition method.

+5
Feb 17 2018-12-17T00:
source share

So, I would like to suggest a small change for @ Geoff's answer.

Instead of having a global static boolean, I would prefer a local non-static one. This is what I came up with.

Create interface

 public interface TransitionAnimator { void disableTransitionAnimation(); void enableTransitionAnimation(); } 

Make the snippet an implementation of this interface.

 public class MyFragment extends Fragment implements TransitionAnimator { private boolean mTransitionAnimation; @Override public void disableTransitionAnimation() { mTransitionAnimation = false; } @Override public void enableTransitionAnimation() { mTransitionAnimation = true; } @Override public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) { Animation result; if (!mTransitionAnimation) { Animation dummyAnimation = new Animation() { }; dummyAnimation.setDuration(0); result = dummyAnimation; } else { result = super.onCreateAnimation(transit, enter, nextAnim); } return result; } 

And then when you want to turn off the transition animation for the fragment, just do

 if (fragment instanceof TransitionAnimator) { ((TransitionAnimator) fragment).disableTransitionAnimation(); } 

to enable them just do

 if (fragment instanceof TransitionAnimator) { ((TransitionAnimator) fragment).enableTransitionAnimation(); } 

If you want to do the same for all fragments in the fragment manager, just do

 List<Fragment> fragments = getSupportFragmentManager().getFragments(); for (Fragment fragment : fragments) { if (fragment instanceof TransitionAnimator) { // disable animations ((TransitionAnimator) fragment).disableTransitionAnimation(); } } 

Very similar, but without static fields.

+1
Jun 25 '16 at 21:06
source share

Just use another overloaded setCustomAnimation() method and in which do not set R.anim.slide_out and this will solve your problem.

Greetings :)

0
Feb 14 '12 at 8:45
source share

Before answering your question, I need to ask the question myself.

In the onBackPressed () method of the second action, can you access the stack of the first action?

If so, then you can call popBackStackImmediate (String trnaisiotnName, int inclusive) and it will remove the fragment transition from the backstack, and you do not need to worry about the animation.

I assume that you can access previous activity, otherwise it will not work

0
Apr 19 '13 at 16:10
source share

This is pretty easy to achieve via overridePendingTransition(int enterAnim, int exitAnim) with 0 without animation.

 FragmentManager fm = getSupportFragmentManager(); if (fm.getBackStackEntryCount() > 0) { fm.popBackStack(); overridePendingTransition(0, 0); } 
0
Mar 20 '16 at 10:43
source share

This is a continuation of the excellent answer to @Geoff, but for a more dynamic and realistic scenario.

I thought it was a good little post, but now I understand that it got a little out of control. However, the code is everything, and I find it really useful, although it covers much more than just turning off transition animations.

Usually when I work with Fragments, I like to have a BaseFragment that attaches to a BaseActivityCallback. This BaseActivityCallback can be used by my fragments to add a new fragment on top of it or even put fragments under it, hence the desire to disable pop animation - or pop quietly:

 interface BaseActivityCallback { void addFragment ( BaseFragment f, int containerResId ); void popFragment ( boolean silently ); } class BaseActivity extends android.support.v4.app.FragmentActivity implements BaseActivityCallback { public void addFragment ( BaseFragment f, int containerResId ) { FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); ft.setCustomAnimations(R.anim.enter, R.anim.exit, R.anim.enter, R.anim.pop_exit); // http://stackoverflow.com/a/17488542/2412477 ft.addToBackStack(DEFAULT_FRAGMENT_STACK_NAME); ft.replace(containerResId, fragment); ft.commitAllowingStateLoss(); } public void popFragment ( boolean silently ) { FragmentManager fm = getSupportFragmentManager(); if ( silently ) { int count = fm.getFragments().size(); BaseFragment f = (BaseFragment)fm.getFragments().get(count-1); f.setDisableTransitionAnimations(true); } fm.popBackStackImmediate(); } } public abstract class BaseFragment extends android.support.v4.app.Fragment { private static final String TAG = "BaseFragment"; private final String STATE_DISABLE_TRANSITION_ANIMATIONS = TAG+".stateDisableTransitionAnimations"; protected BaseActivityCallback baseActivityCallback; private boolean disableTransitionAnimations; @Override public void onCreate ( @Nullable Bundle savedInstanceState ) { super.onCreate(savedInstanceState); disableTransitionAnimations = (savedInstanceState==null ? false : savedInstanceState.getBoolean(STATE_DISABLE_TRANSITION_ANIMATIONS, false)); } @Override public void onAttach ( Context context ) { super.onAttach(context); baseActivityCallback = (BaseActivityCallback)context; } @Override public void onSaveInstanceState ( Bundle outState ) { super.onSaveInstanceState(outState); outState.putBoolean(STATE_DISABLE_TRANSITION_ANIMATIONS, disableTransitionAnimations); } @Override public Animation onCreateAnimation ( int transit, boolean enter, int nextAnim ) { if ( disableTransitionAnimations ) { Animation nop = new Animation(){}; nop.setDuration(0); return nop; } return super.onCreateAnimation(transit, enter, nextAnim); } public void setDisableTransitionAnimations ( boolean disableTransitionAnimations ) { this.disableTransitionAnimations = disableTransitionAnimations; // http://stackoverflow.com/a/11253987/2412477 } } 

Now you can create your MainActivity and show that Fragment1 , which can add another Fragment2 , which can in turn pop Fragment1 :

 public class MainActivity extends BaseActivity { protected void onCreate ( Bundle savedInstanceState ) { setContentView(R.layout.main_activity); ... if ( getSupportFragmentManager().getFragments() != null && !getSupportFragmentManager().getFragments().isEmpty() ) { addFragment( FragmentA.newInstance(), R.id.main_activity_fragment_container ); } } ... } public class FragmentA extends BaseFragment { public View onCreateView ( LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState ) { ViewGroup root = (ViewGroup)inflater.inflate(R.layout.fragment_a, container, false); ... root.findViewById(R.id.fragment_a_next_button) .setOnClickListener( new View.OnClickListener() { public void onClick ( View v ) { baseActivityCallback.addFragment( FragmentB.newInstance(), R.id.main_activity_fragment_container ); } }); } } public class FragmentB extends BaseFragment { public View onCreateView ( LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState ) { ViewGroup root = (ViewGroup)inflater.inflate(R.layout.fragment_b, container, false); ... root.findViewById(R.id.fragment_b_pop_silently_button) .setOnClickListener( new View.OnClickListener() { public void onClick ( View v ) { baseActivityCallback.popFragment( true ); } }); } } 
0
Sep 05 '16 at 19:41
source share

Discard this in the fragment you want to output without animation, and save the animation as you type

 @Override public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) { if(!enter){ Animation a = new Animation() {}; a.setDuration(0); return a; } return super.onCreateAnimation(transit, enter, nextAnim); } 
0
Oct 02 '17 at 2:42 on
source share

A simpler solution:

 for (fragment in supportFragmentManager.fragments) { removeFragment(fragment) } if (supportFragmentManager.backStackEntryCount > 0) { supportFragmentManager.popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE) } 
0
Feb 21 '19 at 11:17
source share

In fact, Android now has a way to do this without @ Geoff's answer.

To prevent the animation from popBackStack() in popBackStack() , when pumping up your fragment add .setReorderingAllowed(true) to your fragmentTransaction .setReorderingAllowed(true) .

For example:

 supportFragmentTransaction.beginTransaction() .setReorderingAllowed(true) .addToBackStack(null) .setCustomAnimations( android.R.anim.fade_in, android.R.anim.fade_out, android.R.anim.fade_in, android.R.anim.fade_out ) .replace(yourContainer.id, yourFragment) .commit() 

You will notice that if you set setReorderingAllowed(true) , the pop animation will no longer play. The results are actually similar to the result of @Geoff's answer.

0
May 03 '19 at 1:22
source share

Reply to comment by Jeff and plackemacher.

You can try to remove all views from this fragment. Then the fragment will be shown, but it should be transparent.

Delete all-1 (I use the navigation box so that the fragment of the box should remain):

  int size = fragmentsList.size ()-1; FragmentTransaction transaction = fragmentManager.beginTransaction (); transaction.setTransition (FragmentTransaction.TRANSIT_NONE); Fragment fragment; for (int i = size ; i > 0 ; i--) { fragment = fragmentsList.get (i); if(fragment != null) { View viewContainer = fragment.getView (); if (viewContainer != null) { ((ViewGroup) viewContainer).removeAllViews (); } transaction.remove (fragment); } } size = fragmentManager.getBackStackEntryCount (); for (int i = 0; i < size ; i++) { fragmentManager.popBackStack (null, FragmentManager.POP_BACK_STACK_INCLUSIVE); } 

sorry for my English

-one
Nov 24 '14 at 19:04
source share



All Articles