Animieren Sie den Übergang zwischen Fragmenten


284

Ich versuche den Übergang zwischen Fragmenten zu animieren. Ich habe die Antwort von den folgenden
Android-Fragmenten und Animationen erhalten

FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.setCustomAnimations(R.anim.slide_in_left, R.anim.slide_out_right);

DetailsFragment newFragment = DetailsFragment.newInstance();

ft.replace(R.id.details_fragment_container, newFragment, "detailFragment");

// Start the animated transition.
ft.commit();

Und mein R.anim.slide_in_left

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
        <translate android:fromXDelta="50%p" android:toXDelta="0"
            android:duration="@android:integer/config_mediumAnimTime"/>
       <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
            android:duration="@android:integer/config_mediumAnimTime" />
</set>

Aber als ich das versuchte, zeigte es sich

02-08 16:27:37.961: ERROR/AndroidRuntime(1717): FATAL EXCEPTION: main
02-08 16:27:37.961: ERROR/AndroidRuntime(1717): java.lang.RuntimeException: Unknown animator name: translate
02-08 16:27:37.961: ERROR/AndroidRuntime(1717):     at android.animation.AnimatorInflater.createAnimatorFromXml(AnimatorInflater.java:129)
02-08 16:27:37.961: ERROR/AndroidRuntime(1717):     at android.animation.AnimatorInflater.createAnimatorFromXml(AnimatorInflater.java:126)
02-08 16:27:37.961: ERROR/AndroidRuntime(1717):     at android.animation.AnimatorInflater.createAnimatorFromXml(AnimatorInflater.java:93)
02-08 16:27:37.961: ERROR/AndroidRuntime(1717):     at android.animation.AnimatorInflater.loadAnimator(AnimatorInflater.java:72)
02-08 16:27:37.961: ERROR/AndroidRuntime(1717):     at android.app.FragmentManagerImpl.loadAnimator(FragmentManager.java:621)
02-08 16:27:37.961: ERROR/AndroidRuntime(1717):     at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:733)
02-08 16:27:37.961: ERROR/AndroidRuntime(1717):     at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:919)
02-08 16:27:37.961: ERROR/AndroidRuntime(1717):     at android.app.BackStackRecord.run(BackStackRecord.java:578)
02-08 16:27:37.961: ERROR/AndroidRuntime(1717):     at android.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1217)

Irgendwelche Ideen? Als ich überprüft habe, ist die Honeycomb API-Referenz translatevorhanden. Was habe ich verpasst?
Gibt es eine andere Möglichkeit, den Übergang zwischen Fragmenten zu animieren? Vielen Dank


benutze ANIMATOR --- nicht Animation! benutze android.R.ANIMATOR.fade_in funktioniert, benutze NICHT android.R.ANIM.fade_in - es hat Verhalten BUGS
user1269737

Antworten:


347

Sie müssen das neue android.animationFramework (Objektanimatoren) mit FragmentTransaction.setCustomAnimationssowie verwenden FragmentTransaction.setTransition.

Hier ist ein Beispiel für die Verwendung setCustomAnimationsvon ApiDemos ' FragmentHideShow.java :

ft.setCustomAnimations(android.R.animator.fade_in, android.R.animator.fade_out);

und hier ist das relevante Animator-XML aus res / animator / fade_in.xml :

<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:interpolator/accelerate_quad"
    android:valueFrom="0"
    android:valueTo="1"
    android:propertyName="alpha"
    android:duration="@android:integer/config_mediumAnimTime" />

Beachten Sie, dass Sie mit mehreren Animatoren <set>genau wie mit dem älteren Animationsframework mehrere Animatoren kombinieren können .


EDIT : Da die Leute nach Slide-In / Slide-Out fragen, werde ich das hier kommentieren.

Einschieben und Herausschieben

Sie können die natürlich animieren translationX, translationY, x, und yEigenschaften, aber in der Regel beinhalten Folien Inhalte zu und von Off-Screen Animieren. Soweit ich weiß, gibt es keine Übergangseigenschaften, die relative Werte verwenden. Dies hindert Sie jedoch nicht daran, sie selbst zu schreiben. Denken Sie daran, dass für Eigenschaftsanimationen lediglich Getter- und Setter-Methoden für die zu animierenden Objekte (in diesem Fall Ansichten) erforderlich sind. Sie können also einfach eigene Methoden getXFractionund setXFractionMethoden für Ihre Ansichtsunterklasse erstellen :

public class MyFrameLayout extends FrameLayout {
    ...
    public float getXFraction() {
        return getX() / getWidth(); // TODO: guard divide-by-zero
    }

    public void setXFraction(float xFraction) {
        // TODO: cache width
        final int width = getWidth();
        setX((width > 0) ? (xFraction * width) : -9999);
    }
    ...
}

Jetzt können Sie die Eigenschaft 'xFraction' folgendermaßen animieren:

res / animator / slide_in.xml :

<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/linear_interpolator"
    android:valueFrom="-1.0"
    android:valueTo="0"
    android:propertyName="xFraction"
    android:duration="@android:integer/config_mediumAnimTime" />

Beachten Sie, dass wenn das Objekt, in dem Sie animieren, nicht die gleiche Breite wie das übergeordnete Objekt hat, die Dinge nicht ganz richtig aussehen. Daher müssen Sie möglicherweise Ihre Eigenschaftsimplementierung an Ihren Anwendungsfall anpassen.


8
Ich habe fade_in und fade_out zum Laufen gebracht, aber die anderen in / res / animator geben Fehler. Und keiner von denen scheint überhaupt zum Ein- und Ausrutschen zu sein. Ich habe versucht, meine eigenen XML-Dateien zu schreiben, um dies zu tun, aber am Ende habe ich nur Fragmente über Fragmenten. Noch etwas Hilfe bitte?
Dave MacLean

Und was ist mit der Übersetzung? Wie führt man eine Übersetzung mit Prozentwerten in einem in XML definierten objectAnimator durch? Es ist mir nicht gelungen, AdapterViewFlipper beim Umblättern mit vertikalen Folienanimationen zu animieren, die in XML definiert sind ...
GBouerat

6
Ich erhalte 11-19 10: 27: 50.912: W / PropertyValuesHolder (23107): Die Methode setXFraction () mit dem Typ float wurde in der Zielklassenklasse android.widget.FrameLayout nicht gefunden. Aber in meinem XML habe ich meine benutzerdefinierte Ansicht MyFrameLayout. Irgendwelche Ideen?
Barkside

13
Eigentlich, Roman, sollte der Rat auch in die andere Richtung gehen: Wenn Sie die Support-Bibliothek verwenden, müssen Sie das alte Animationsframework (android.R.anim) mit FragmentTransaction.setCustomAnimations ao
pjv

1
@RomanNurik Diese Antwort funktionierte auf den meisten Geräten hervorragend, aber für einige Benutzer (insbesondere für einige Samsung Galaxy S3 / 4-Telefone) wurde die Breite während der Animationen aus irgendeinem Grund nicht gemeldet, sodass das Fragment nie angezeigt wurde. Ich konnte es für diese Benutzer mit einem OnPredrawListener zum Laufen bringen, wie hier gezeigt: mavyasoni9891.blogspot.com/2014/06/…
ajpolt

188

Ich habe so gemacht:

Fügen Sie diese Methode hinzu , um Fragmente durch Animationen zu ersetzen :

public void replaceFragmentWithAnimation(android.support.v4.app.Fragment fragment, String tag){
    FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
    transaction.setCustomAnimations(R.anim.enter_from_left, R.anim.exit_to_right, R.anim.enter_from_right, R.anim.exit_to_left);
    transaction.replace(R.id.fragment_container, fragment);
    transaction.addToBackStack(tag);
    transaction.commit();
}

Sie müssen hinzufügen vier Animationen in Anim Ordner, ist Associate mit Ressource :

enter_from_left.xml :

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:shareInterpolator="false">
    <translate
        android:fromXDelta="-100%" android:toXDelta="0%"
        android:fromYDelta="0%" android:toYDelta="0%"
        android:duration="700"/>
</set>

exit_to_right.xml :

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:shareInterpolator="false">
    <translate
        android:fromXDelta="0%" android:toXDelta="100%"
        android:fromYDelta="0%" android:toYDelta="0%"
        android:duration="700" />
</set>

enter_from_right.xml :

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:shareInterpolator="false">
    <translate
        android:fromXDelta="100%" android:toXDelta="0%"
        android:fromYDelta="0%" android:toYDelta="0%"
        android:duration="700" />
</set>

exit_to_left.xml :

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:shareInterpolator="false">
    <translate
        android:fromXDelta="0%" android:toXDelta="-100%"
        android:fromYDelta="0%" android:toYDelta="0%"
        android:duration="700"/>
</set>

Ausgabe:

Geben Sie hier die Bildbeschreibung ein

Es ist fertig .


14
Tolle Lösung. Ich bin mir jedoch nicht sicher, warum Sie die Anweisungen gegen RTL ausgetauscht haben. Meine Methode:.setCustomAnimations(R.anim.enter_from_right, R.anim.exit_to_left, R.anim.enter_from_left, R.anim.exit_to_right)
zed

2
Tolle Lösung. Ein ähnlicher Ansatz und dieselben Animationsdateien funktionieren für Übergänge zwischen Aktivitäten.
Stan

1
@ MikeZriel, res -> anim -> setzen Sie Ihre XML hier
Hiren Patel

3
Danke Hiren, ich ändere die Geschwindigkeit (700) auf (300) viel besser und eher wie iOS
Mike Zriel

3
LOL, ich kam mit Lösung zurück. Ich habe android.app.fragment und FragmentManager für jede Java-Klasse importiert. Nachdem ich einige Materialien überprüft hatte, stellte ich fest, dass für die Verwendung von 'setCustomAnimations ()' die android.support.v4-Bibliothek importiert werden muss. wichtig zu sagen, das sollte 'support.v4.app' sein! Ich habe alle Methoden 'getFragmentManager ()' durch 'getSupportFragmentManager ()' und den gesamten Import 'android.app.Fragment / FragmentManager ...' in 'android.support.v4.app ....' ersetzt Die Animation begann ohne Absturz gut zu funktionieren ... Wenn ihr in ähnlichen Fällen festsitzt, lest meine Lösung. Thx Hiren Patel xD
KoreanXcodeWorker

58

Wenn Sie es sich leisten können, sich nur an Lollipop und später zu binden, scheint dies den Trick zu tun:

import android.transition.Slide;
import android.util.Log;
import android.view.Gravity;
.
.
.
f = new MyFragment();
f.setEnterTransition(new Slide(Gravity.RIGHT));
f.setExitTransition(new Slide(Gravity.LEFT));
getFragmentManager()
    .beginTransaction()
    .replace(R.id.content, f, FRAG_TAG)  // FRAG_TAG is the tag for your fragment
    .commit();

Hoffe das hilft.


1
Dies wird zwar auf Lollipop erreicht, ist jedoch kaum praktikabel, da der Prozentsatz der Geräte, auf denen Lollipop ausgeführt wird, vernachlässigbar ist (derzeit verwenden 1,6% der Android-Geräte Lollipop).
Eran Goldin

1
new Slide(...): Aufruf erfordert API Level 21
Chintan Soni

Wofür steht getKey ()?
Alvaro

13
@EranGoldin Nichts hält ewig. Würden Sie sich heute über eine Lösung nur für Android 2.0+ lustig machen?
Tom

@ Tom du hast einen Punkt. Wenn Ihre App jedoch eine große Benutzerbasis hat, können Sie die API-Ebene nicht einfach erhöhen. Wenn die meisten Ihrer Benutzer Ihre App danach nicht mehr ausführen können, ist dies überhaupt keine Lösung.
Eran Goldin

47

Nurik ‚s Antwort war sehr hilfreich, aber ich konnte es nicht an der Arbeit , bis ich fand diese . Kurz gesagt, wenn Sie die Kompatibilitätsbibliothek verwenden (z. B. SupportFragmentManager anstelle von FragmentManager), unterscheidet sich die Syntax der XML-Animationsdateien.


28

Hier ist eine Animation zum Ein- und Ausziehen zwischen Fragmenten:

FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.setCustomAnimations(R.animator.enter_anim, R.animator.exit_anim);
transaction.replace(R.id.listFragment, new YourFragment());
transaction.commit();

Wir verwenden einen objectAnimator.

Hier sind die beiden XML-Dateien im Animator- Unterordner.

enter_anim.xml

<?xml version="1.0" encoding="utf-8"?>
<set>
     <objectAnimator
         xmlns:android="http://schemas.android.com/apk/res/android"
         android:duration="1000"
         android:propertyName="x"
         android:valueFrom="2000"
         android:valueTo="0"
         android:valueType="floatType" />
</set>

exit_anim.xml

<?xml version="1.0" encoding="utf-8"?>
<set>
    <objectAnimator
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:duration="1000"
        android:propertyName="x"
        android:valueFrom="0"
        android:valueTo="-2000"
        android:valueType="floatType" />
</set>

Ich hoffe das würde jemandem helfen.


37
Das Verschieben der Ansicht für 2000 Pixel ist eine sehr hässliche Lösung.
carlo.marinangeli

4
Das exit_anim "erscheint" für mich nur vom Bildschirm, es wird nicht über den Bildschirm zurück animiert. Irgendwelche Ideen? Ich benutze.setCustomAnimations(R.animator.slide_in_left, R.animator.slide_out_right, R.animator.slide_in_left, R.animator.slide_out_right)
Herr Pablo

@ MrPablo, der Grund ist wahrscheinlich, dass Sie den obigen Code nicht kopiert und eingefügt haben. setCustomAnimations sollte vor der Ersetzungsmethode aufgerufen werden.
Galya

Wenn ich in diesem Fall ein anderes Fragment durch eine Animation ersetze und die App unmittelbar vor dem Zeitlimit oder der Dauer der Animation minimiere und wieder zur Anwendung zurückkehre, werden das vorherige Fragment und das aktuelle Fragment parallel angezeigt.
Prinz

23

Stellen Sie für alle anderen Personen, die erwischt werden, sicher, dass setCustomAnimations vor dem Aufruf aufgerufen wird, um beim Erstellen der Transaktion zu ersetzen / hinzuzufügen.


12

Android SDK Implementierung von FragmentTransaction will eine AnimatorWeile Support-Bibliothek will eine Animation, frag mich nicht warum, aber nach Strangeluks Kommentar habe ich in Android 4.0.3 Code und Support-Bibliothek gesucht. Android SDK verwendet loadAnimator()und unterstützt Bibliothek verwendetloadAnimation()


7

Versuchen Sie es mit dieser einfachen und schnellen Lösung. Android bietet einige Standardeinstellungen animation.

fragmentTransaction.setCustomAnimations(android.R.anim.slide_in_left, android.R.anim.slide_out_right);

FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.setCustomAnimations(android.R.anim.slide_in_left, android.R.anim.slide_out_right);
fragmentManager.addOnBackStackChangedListener(this);
fragmentTransaction.replace(R.id.frame, firstFragment, "h");
fragmentTransaction.addToBackStack("h");
fragmentTransaction.commit();

Ausgabe:

Geben Sie hier die Bildbeschreibung ein


Woow .. das sollte die akzeptierte Antwort sein !! Eine einfache und elegante Lösung. Es ist sehr glatt im Vergleich zu den anderen schlägt Antworten vor
Chathura Buddhika
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.