Frammenti e animazioni Android


265

Come dovresti implementare il tipo di scorrimento che ad esempio utilizza il client Honeycomb Gmail?

Può TransactionManagergestirlo automaticamente aggiungendo e rimuovendo i frammenti, è un po 'difficile testarlo a causa dell'emulatore che è una presentazione :)

Risposte:


388

Per animare la transizione tra i frammenti o per animare il processo di mostrare o nascondere un frammento, si utilizza Fragment Managerper creare un Fragment Transaction.

All'interno di ciascuna Transazione di frammenti è possibile specificare animazioni in entrata e in uscita che verranno utilizzate rispettivamente per mostrare e nascondere (o entrambe quando si usa la sostituzione).

Il codice seguente mostra come sostituire un frammento estraendo un frammento e facendo scorrere l'altro al suo posto.

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

Per ottenere la stessa cosa nascondendo o mostrando un frammento che chiameresti semplicemente ft.showo ft.hide, passando nel frammento che desideri mostrare o nascondere rispettivamente.

Per riferimento, le definizioni di animazione XML utilizzerebbero il objectAnimatortag. Un esempio di slide_in_left potrebbe assomigliare a questo:

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

57
Quando l'ho provato, mostra RuntimeException: nome animatore sconosciuto: tradurre .
— Labeeb Panampullan,

3
Assicurati che le animazioni definite in slide_in_left e right siano costruite usando una serie di definizioni objectAnimator piuttosto che la vecchia definizione di animazione.
— Reto Meier,

7
Questo ha aiutato molto. Ero sulla strada giusta, ma non sono arrivato fino in fondo. Per gli altri lettori, potresti anche avere android: interpolator come attributo, con il tuo preferito preferito specificato (come "@android: interpolator / linear"). L'impostazione predefinita è "@android: interpolator / accelerate_decelerate".
— Dave MacLean,

6
Sto prendendo di mira l'API Level 7 con le API di compatibilità. C'è un modo per animare i frammenti?
— Jarrod Smith,

5
@JarrodSmith puoi provare a utilizzare una libreria di compatibilità come NineOldAndroids per portare l'API Honeycomb su Eclair.
— Mr. S

249

Se non devi usare la libreria di supporto, dai un'occhiata alla risposta di Roman .

Ma se si desidera utilizzare la libreria di supporto, è necessario utilizzare il vecchio framework di animazione come descritto di seguito.

Dopo aver consultato le risposte di Reto e blindstuff, ho ottenuto il seguente codice funzionante.

I frammenti appaiono scivolando da destra e scivolando verso sinistra quando si preme indietro.

FragmentManager fragmentManager = getSupportFragmentManager();

FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.setCustomAnimations(R.anim.enter, R.anim.exit, R.anim.pop_enter, R.anim.pop_exit);

CustomFragment newCustomFragment = CustomFragment.newInstance();
transaction.replace(R.id.fragment_container, newCustomFragment );
transaction.addToBackStack(null);
transaction.commit();

L'ordine è importante Questo significa che devi chiamare setCustomAnimations()prima replace()o l'animazione non avrà effetto!

Successivamente questi file devono essere inseriti nella cartella res / anim .

enter.xml :

<?xml version="1.0" encoding="utf-8"?>
<set>
    <translate xmlns:android="http://schemas.android.com/apk/res/android"
               android:fromXDelta="100%"
               android:toXDelta="0"
               android:interpolator="@android:anim/decelerate_interpolator"
               android:duration="@android:integer/config_mediumAnimTime"/>
</set>

exit.xml :

<set>
    <translate xmlns:android="http://schemas.android.com/apk/res/android"
               android:fromXDelta="0"
               android:toXDelta="-100%"
               android:interpolator="@android:anim/accelerate_interpolator"
               android:duration="@android:integer/config_mediumAnimTime"/>
</set>

pop_enter.xml :

<set>
    <translate xmlns:android="http://schemas.android.com/apk/res/android"
               android:fromXDelta="-100%"
               android:toXDelta="0"
               android:interpolator="@android:anim/decelerate_interpolator"
               android:duration="@android:integer/config_mediumAnimTime"/>
</set>

pop_exit.xml :

<?xml version="1.0" encoding="utf-8"?>
<set>
    <translate xmlns:android="http://schemas.android.com/apk/res/android"
               android:fromXDelta="0"
               android:toXDelta="100%"
               android:interpolator="@android:anim/accelerate_interpolator"
               android:duration="@android:integer/config_mediumAnimTime"/>
</set>

La durata delle animazioni può essere modificata in uno dei valori predefiniti come @android:integer/config_shortAnimTimeo in qualsiasi altro numero.

Si noti che se tra le sostituzioni di frammenti si verifica una modifica della configurazione (ad esempio rotazione) l'azione posteriore non viene animata. Questo è un bug documentato che esiste ancora nel rev 20 della libreria di supporto.


47
Questo mi ha appena salvato. Nota, prestare attenzione all'ordine è importante , che, naturalmente, ho perso la prima volta. Questo significa che devi chiamare setCustomAnimations () prima di sostituire ().
— Stephen Kidson,

3
Ho cercato di implementare i miei frammenti. Ho scritto tutto come hai detto, ma logcat dice: sconosciuto nome animatore tradurre Come posso risolvere questo problema? A proposito, sto chiamando il mio frammento su Navigation Drawer (Menu scorrevole)
— Zafer Celaloglu,

Funziona alla grande ma si scopre che la creazione di questo con gli strumenti di creazione 21.1 genera un errore che dice "Nome file non valido: deve contenere solo lettere minuscole e cifre ([a-z0-9_.])". Suggerisco di modificare i nomi dei file nella risposta a pop_enter.xml e pop_exit.xml.
— Smichak,

Ottima soluzione e funziona benissimo quando premo il pulsante Indietro. Ho solo una domanda: se voglio creare un backButton personalizzato, quale codice dovrei chiamare per replicare il comportamento dal pulsante back?
— Thomas Teilmann,

1
Thomas, se vuoi tornare indietro, dovresti implementare questo modulo: .setCustomAnimations (R.anim.pop_enter, R.anim.pop_exit, R.anim.enter, R.anim.exit)
— Alex Zaraos

26

Consiglio vivamente di usare questo invece di creare il file di animazione perché è una soluzione molto migliore. Android Studio fornisce già impostazioni predefinite che animation è possibile utilizzare senza creare alcun nuovo file XML. I nomi delle animazioni sono android.R.anim.slide_in_left e android.R.anim.slide_out_right e puoi usarli come segue:

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


1
android.R ... "Android Studio fornisce un'animazione predefinita", che non è per Android Studio, ma può funzionare anche in eclissi, Android.R è specifico per Android. E dal modo in cui non hai condiviso le informazioni su cosa hanno le API. roba su android.R sono diversi su diverse API.
— Steve Moretz,

@stevemoretz thaxs bro Ho concordato il tuo punto .. Correggerò e aggiornerò la mia risposta ...
— Gowthaman M

5

La mia libreria di supporto modificata supporta l'utilizzo di Visualizza animazioni (ad es. <translate>, <rotate>) E Animatori di oggetti (ad es. <objectAnimator>) Per le Transizioni di frammenti. È implementato con NineOldAndroids . Fare riferimento alla mia documentazione su Github per i dettagli.


2

Per quanto mi riguarda, ho bisogno della direzione di visualizzazione:

in -> scorri da destra

fuori -> scorri verso sinistra

Qui funziona per me il codice:

slide_in_right.xml

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

slide_out_left.xml

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

codice transazione:

inline fun FragmentActivity.setContentFragment(
        containerViewId: Int,
        backStack: Boolean = false,
        isAnimate: Boolean = false,
        f: () -> Fragment

): Fragment? {
    val manager = supportFragmentManager
    return f().apply {
        manager.beginTransaction().let {
            if (isAnimate)
                it.setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left)

            if (backStack) {
                it.replace(containerViewId, this, "Fr").addToBackStack("Fr").commit()
            } else {
                it.replace(containerViewId, this, "Fr").commit()
            }
        }
    }
}

Android sembra sfarfallare le transizioni con quelle animazioni (specialmente quelle tradotte)
— Gabriel De Oliveira Rohden

@GabrielDeOliveiraRohden come per me non in tutti i sensi
— Serg Burlaka

1

Lo risolvo nel modo seguente

Animation anim = AnimationUtils.loadAnimation(this, R.anim.slide);
fg.startAnimation(anim);
this.fg.setVisibility(View.VISIBLE); //fg is a View object indicate fragment
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.