Pop das Fragment-Backstack, ohne die Pop-Animation zu spielen

Ich schiebe ein Fragment auf den Fragmentstapel mit folgendem 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(); 

Auf diese Weise wird, wenn der Fragmentstapel geknallt wird, zB durch Drücken der Back-Taste, eine Fragment-Pop-Animation gespielt. Allerdings gibt es Situationen, in denen ich den Fragment-Backstack knacken möchte, ohne diese Animation zu zeigen, zB weil ich gerade von einer anderen Aktivität zurückgekehrt bin und das vorherige Fragment sofort ohne Animation anzeigen möchte.

Eine Beispielnavigation könnte so aussehen:

  • Der Benutzer befindet sich auf dem Startbildschirm mit dem Wurzelfragment
  • Er wählt ein Element auf dem Wurzelfragment aus, das dann ein neues Fragment anzeigt, um Details dieses Elements anzuzeigen. Es handelt sich dabei um eine Fragment-Transaktion, die sowohl für den Push- als auch den Pop-Case Animationen setzt (also wenn der Benutzer den Back-Button drückt, wird der Übergang animiert)
  • Aus diesem Fragment beginnt er eine Aktivität, die (aus welchem ​​Grund auch immer) das gerade gezeigte Element löscht
  • Wenn diese Aktivität beendet ist, möchte ich gerne in das Wurzelfragment zurückkehren, ohne die "Pop-Animation" des "Detail-Fragments"

Gibt es eine Möglichkeit, den Fragment-Backstack zu knacken, ohne die angegebene Pop-Animation zu spielen?

  • Unterschied zwischen add (), replace () und addToBackStack ()
  • Fragment customAnimation funktioniert nicht in Lollipop
  • Implementiere einen DatePicker in einem Fragment
  • Fragment's onActivityCreated () wird nach onDestroy () der Aktivität aufgerufen
  • Android 1.6 & Fragment & Tabhost
  • Doppeltes Fragment, das Android mit ActionBar dreht
  • Fragmente in Android 2.2.1, 2.3, 2.0. Ist das möglich?
  • Einseitige PräferenzAktivität ohne Header / Fragmente?
  • 9 Solutions collect form web for “Pop das Fragment-Backstack, ohne die Pop-Animation zu spielen”

    Also war Warpzit auf dem richtigen Weg, er hat sich auch nicht genau mit deiner spezifischen Frage beschäftigt. Ich stieß auf genau das gleiche Problem und hier ist, wie ich es gelöst habe.

    Zuerst habe ich eine statische Boolesche Variable erstellt (um der Einfachheit willen, lass es in die FragmentUtils-Klasse setzen) …

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

    Dann, in JEDEM Fragment, das du hast, musst du die onCreateAnimation-Methode überschreiben …

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

    Dann, wenn Sie den Backstack aus Ihrer Tätigkeit löschen müssen, machen Sie einfach die folgenden …

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

    Und voila, ein Aufruf von clearBackStack () wird dich in das Wurzelfragment ohne Übergangsanimationen zurückführen.

    Hoffentlich wird das große G eine weniger dumme Art und Weise hinzufügen, dies in der Zukunft zu tun.

    Also für die Support-Bibliothek nach Arbeiten:

    In dem Fragment, das eine benutzerdefinierte Pop-Animation haben sollte, überschreibt man die onCreateAnimation mit deiner eigenen benutzerdefinierten. Sie könnten es bekommen und legen Sie eine Art von Parameter je nachdem, was Sie wollen. Möglicherweise muss man etwas extra Arbeit machen, um es mit regelmäßigen Fragmenten zu machen.

    Hier ist das Beispiel, wo ich es überschreibe und die eingestellte Dauer ändere:

     @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 { } 

    Der Benutzer befindet sich auf dem Startbildschirm mit dem Wurzelfragment

    Lets sagen, das Wurzelfragment ist in der Aktivität A enthalten.

    Er wählt ein Element auf dem Wurzelfragment aus, das dann ein neues Fragment anzeigt, um Details dieses Elements anzuzeigen. Es handelt sich dabei um eine Fragment-Transaktion, die sowohl für den Push- als auch den Pop-Case Animationen setzt (also wenn der Benutzer den Back-Button drückt, wird der Übergang animiert)

    Die Transaktion wird dem hinteren Stack hinzugefügt. Was bedeutet, dass, wenn die Back-Taste aus Detail Fragment gedrückt wird, ist der Knallprozess animiert.

    Aus diesem Fragment beginnt er eine Aktivität, die (aus welchem ​​Grund auch immer) das gerade gezeigte Element löscht.

    Lets sagen, es ist Aktivität B

    Wenn diese Aktivität beendet ist, möchte ich gerne in das Wurzelfragment zurückkehren, ohne die "Pop-Animation" des "Detail-Fragments"

    Eine Möglichkeit, dieses Verhalten zu bekommen, ist dies in der Aktivität 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(); 

    Dies startet die Aktivität A, die sie nach der Dokumentation in ihren Wurzelzustand zurücksetzt (siehe letzter Absatz im Abschnitt "Dieser Startmodus kann auch in Verbindung mit FLAG_ACTIVITY_NEW_TASK: ……" )

    Mit dieser Konfiguration ist die Animation im Standardfall vorhanden, während Sie im Sonderfall die Animation mit:

     intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); 

    Das beginnt neue Aktivität ohne Animationen. Wenn du eine Animation wünschst, kannst du es mit der overridePendingTransition Methode machen.

    Also, ich möchte eine kleine Änderung der Antwort von @ Geoff vorschlagen.

    Anstatt eine globale statische Boolesche zu haben, hätte ich lieber eine lokale nicht-statische. Dies ist, was ich kam mit.

    Erstellen Sie eine Schnittstelle

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

    Machen Sie das Fragment implementieren diese Schnittstelle.

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

    Und dann, wenn du die Übergangsanimationen für ein Fragment deaktivieren möchtest, mach einfach nur

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

    Um es ihnen zu ermöglichen, einfach zu tun

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

    Wenn du das Gleiche für alle Fragmente im Fragment-Manager machen willst, mach einfach

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

    Sehr ähnlich, aber ohne statische Felder.

    Verwenden Sie einfach eine andere überladene Methode von setCustomAnimation() und in dem nicht die R.anim.slide_out gesetzt und das wird Ihr Problem lösen

    Prost 🙂

    Bevor ich deine Frage beantworte, muss ich selbst eine Frage stellen.

    In der Methode onBackPressed () der zweiten Aktivität kannst du auf den Backstack der ersten Aktivität zugreifen?

    Wenn ja, dann kannst du popBackStackImmediate (String trnaisiotnName, int inclusive) anrufen und es wird den Fragmentübergang aus dem Backstack entfernen und du brauchst dir keine Sorgen um Animationen zu machen.

    Ich gehe davon aus, dass Sie auf den Backstack der vorherigen Aktivität zugreifen können, sonst wird das nicht funktionieren

    Dies ist ziemlich einfach durch overridePendingTransition(int enterAnim, int exitAnim) mit beiden 0 für keine Animation zu erreichen.

     FragmentManager fm = getSupportFragmentManager(); if (fm.getBackStackEntryCount() > 0) { fm.popBackStack(); overridePendingTransition(0, 0); } 

    Dies ist ein Nachfolger von @ Geoffs exzellenter Antwort, aber für ein dynamischeres und real-live-Szenario.

    Ich stellte mir vor, dass dies eine nette kleine Post ist, aber ich merke jetzt, dass es ein wenig aus der Hand kam. Allerdings ist der Code alles da und ich finde es wirklich nützlich, obwohl es viel mehr deckt als nur, wie man Übergangsanimationen deaktiviert.

    Normalerweise, wenn ich mit Fragmenten arbeite, habe ich gern ein BaseFragment, das an einem BaseActivityCallback anhängt. Dieser BaseActivityCallback kann von den My Fragments verwendet werden, um ein neues Fragment auf sich selbst zu setzen, oder sogar Pop-Fragmente darunter zu sehen, also der Wunsch, Pop-Animationen zu deaktivieren – oder Pop leise :

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

    Jetzt können Sie Ihre MainActivity erstellen und haben, dass eine Fragment1 die ein weiteres Fragment2 hinzufügen kann, die wiederum Pop- Fragment1 schweigen können :

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

    Antwort auf Geoff und plackemacher Kommentar.

    Sie können versuchen, alle Ansichten aus diesem Fragment zu entfernen. Dann wird Fragment zeigen, aber es sollte transparent sein.

    Entfernen Sie alle-1 (ich benutze navigate Schublade so Schublade Fragment sollte bleiben) Fragment:

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

    Entschuldigung für mein Englisch

    Das Android ist ein Google Android Fan-Website, Alles über Android Phones, Android Wear, Android Dev und Android Spiele Apps und so weiter.