Animare la transizione tra i frammenti


284

Sto cercando di animare la transizione tra i frammenti. Ho ricevuto la risposta dai seguenti
frammenti e animazioni Android

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

E il mio 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>

Ma quando ho provato questo ha mostrato

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)

Qualche idea? Quando ho controllato il riferimento API Honeycomb translateè lì. Cosa mi sono perso?
C'è un altro modo per animare la transizione tra i frammenti? Grazie


usa ANIMATOR --- no Animation! usa android.R.ANIMATOR.fade_in funziona, NON usare android.R.ANIM.fade_in - ha
BUG

Risposte:


348

È necessario utilizzare il nuovo android.animationframework (animatori di oggetti) con FragmentTransaction.setCustomAnimationse FragmentTransaction.setTransition.

Ecco un esempio sull'uso setCustomAnimationsdal FragmentHideShow.java di ApiDemos :

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

ed ecco l'XML animatore rilevante da 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" />

Nota che puoi combinare più animatori usando <set>, proprio come potresti fare con il vecchio framework di animazione.


EDIT : Dal momento che le persone chiedono slide-in / slide-out, commenterò qui.

Slide-in e slide-out

Ovviamente si può animare i translationX, translationY, x, e yle proprietà, ma in genere le diapositive coinvolgere animare contenuti da e fuori dallo schermo. Per quanto ne so non ci sono proprietà di transizione che utilizzano valori relativi. Tuttavia, questo non ti impedisce di scriverli da soli. Ricorda che le animazioni di proprietà richiedono semplicemente metodi getter e setter sugli oggetti che stai animando (in questo caso le viste), quindi puoi semplicemente creare i tuoi metodi getXFractione quelli setXFractionnella sottoclasse della vista, come questo:

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

Ora puoi animare la proprietà 'xFraction', in questo modo:

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" />

Nota che se l'oggetto che stai animando non ha la stessa larghezza del suo genitore, le cose non sembreranno del tutto corrette, quindi potresti dover modificare l'implementazione della proprietà per adattarla al tuo caso d'uso.


8
Ho fatto funzionare fade_in e fade_out, ma gli altri in / res / animator danno errori. E nessuno di questi sembra nemmeno essere per scivolare dentro e scivolare fuori. Ho provato a scrivere i miei xml per fare questo, ma tutto quello che finisco con sono frammenti in cima a frammenti. Qualche altro aiuto per favore?
Dave MacLean,

E la traduzione? Come si fa a definire una traduzione con valori in percentuale in un objectAnimator in XML, per favore? Non sono riuscito ad animare AdapterViewFlipper durante il lancio con le animazioni delle diapositive verticali definite in xml ...
GBouerat

6
Sto ottenendo 11-19 10: 27: 50.912: W / PropertyValuesHolder (23107): Metodo setXFraction () con tipo float non trovato nella classe di classe android.widget.FrameLayout. Ma nel mio XML ho la mia vista personalizzata MyFrameLayout. Qualche idea?
Corteccia

13
In realtà, Roman, il consiglio dovrebbe andare anche dall'altra parte: quando si utilizza la libreria di supporto, è necessario utilizzare il vecchio framework di animazione (android.R.anim) con FragmentTransaction.setCustomAnimations ao
pjv

1
@RomanNurik questa risposta ha funzionato alla grande sulla maggior parte dei dispositivi, ma per alcuni utenti (in particolare su alcuni telefoni Samsung Galaxy S3 / 4) la larghezza non è stata segnalata durante le animazioni per qualche motivo, facendo sì che il frammento non appaia mai. Sono stato in grado di farlo funzionare per quegli utenti utilizzando un OnPredrawListener come mostrato qui: mavyasoni9891.blogspot.com/2014/06/…
ajpolt

188

Ho fatto così:

Aggiungi questo metodo per sostituire i frammenti con le animazioni :

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

Devi aggiungere quattro animazioni nella cartella anim che è associata alla risorsa :

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>

Produzione:

inserisci qui la descrizione dell'immagine

Fatto .


14
Ottima soluzione Tuttavia, non sono sicuro del motivo per cui hai scambiato le indicazioni per RTL. Il mio metodo:.setCustomAnimations(R.anim.enter_from_right, R.anim.exit_to_left, R.anim.enter_from_left, R.anim.exit_to_right)
zed

2
Soluzione eccezionale. Approccio simile e gli stessi file di animazione funzionano per le transizioni tra attività.
Stan,

1
@MikeZriel, res -> anim -> metti qui il tuo xml
Hiren Patel

3
Grazie Hiren, cambio la velocità da (700) a (300) molto meglio e più come iOS
Mike Zriel

3
LOL, sono tornato con una soluzione. Stavo importando android.app.fragment e FragmentManager su ogni classe java. Dopo aver verificato alcuni materiali, ho scoperto che l'uso di 'setCustomAnimations ()' richiede l'importazione della libreria android.support.v4. importante dire che dovrebbe essere 'support.v4.app'! Ho sostituito tutti i metodi 'getFragmentManager ()' con 'getSupportFragmentManager ()' e tutti i file importati 'android.app.Fragment / FragmentManager ...' in 'android.support.v4.app ....', quindi questo l'animazione ha iniziato a funzionare bene senza crash ... Se siete bloccati in casi simili, leggete la mia soluzione. Thx Hiren Patel xD
KoreanXcodeWorker

58

Se puoi permetterti di legarti solo a Lollipop e in seguito, questo sembra fare il trucco:

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

Spero che questo ti aiuti.


1
Anche se questo lo raggiungerà su Lollipop, non è pratico poiché la percentuale di dispositivi che eseguono Lollipop è trascurabile (attualmente l'1,6% dei dispositivi Android esegue Lollipop).
Eran Goldin,

1
new Slide(...): la chiamata richiede il livello API 21
Chintan Soni il

cosa significa getKey ()?
Alvaro

13
@EranGoldin Nulla dura per sempre .. Vuoi deridere una sola soluzione per Android 2.0+ oggi?
Tom,

@Tom hai un punto. Tuttavia, quando la tua app ha una vasta base di utenti, non puoi semplicemente superare il livello API. Se la maggior parte dei tuoi utenti non sarà più in grado di eseguire la tua app dopo, questa non è affatto una soluzione.
Eran Goldin,

47

Nurik 's risposta è stata molto utile, ma non ho potuto farlo funzionare finché non ho trovato questo . In breve, se si utilizza la libreria di compatibilità (ad esempio SupportFragmentManager anziché FragmentManager), la sintassi dei file di animazione XML sarà diversa.


28

Ecco un'animazione slide in / out tra i frammenti:

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

Stiamo usando un objectAnimator.

Ecco i due file XML nella sottocartella animatore .

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>

Spero che possa aiutare qualcuno.


37
spostare la vista per 2000 px, è una soluzione molto brutta.
carlo.marinangeli,

4
Exit_anim si "stacca" dallo schermo per me, non si anima indietro sullo schermo. Qualche idea? Sto usando.setCustomAnimations(R.animator.slide_in_left, R.animator.slide_out_right, R.animator.slide_in_left, R.animator.slide_out_right)
Signor Pablo il

@MrPablo, il motivo è probabilmente che non hai copiato il codice sopra. setCustomAnimations deve essere chiamato prima del metodo di sostituzione.
Galya,

In questo caso, se rimpiazzo un altro frammento con l'animazione e minimizzo l'app immediatamente prima del timeout o della durata dell'animazione e ritorni nuovamente all'applicazione, visualizzerà il frammento precedente e il frammento corrente in parallelo.
Prince

23

Per chiunque venga catturato, assicurarsi che setCustomAnimations sia chiamato prima della chiamata per sostituire / aggiungere durante la creazione della transazione.


12

L'implementazione dell'SDK per Android di FragmentTransaction richiede un Animatorpo 'di tempo alla libreria di supporto Animation, non chiedermi perché, ma dopo il commento di strangeluk ho esaminato il codice di Android 4.0.3 e la libreria di supporto. SDK Android utilizza loadAnimator()e supporta gli usi delle librerieloadAnimation()


7

Prova a utilizzare questa soluzione semplice e veloce. Android fornisce alcuni messaggi predefiniti 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();

Produzione:

inserisci qui la descrizione dell'immagine


Caspita .. questa dovrebbe essere la risposta accettata !! Una soluzione semplice ed elegante. È molto fluido rispetto agli altri suggerisce risposte
Chathura Buddhika
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.