Fragments et animation Android

265

Comment mettre en œuvre le type de glissement utilisé par exemple par le client Honeycomb Gmail?

Peut TransactionManagergérer cela automatiquement en ajoutant et en supprimant les fragments, il est assez difficile de tester cela car l'émulateur est un diaporama :)

alexanderblom
la source

Réponses:

388

Pour animer la transition entre les fragments, ou pour animer le processus d'affichage ou de masquage d'un fragment, vous utilisez le Fragment Managerpour créer un Fragment Transaction.

Dans chaque transaction de fragment, vous pouvez spécifier des animations d'entrée et de sortie qui seront utilisées respectivement pour afficher et masquer (ou les deux lorsque le remplacement est utilisé).

Le code suivant montre comment remplacer un fragment en faisant glisser un fragment et en faisant glisser l'autre à sa place.

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

Pour réaliser la même chose en cachant ou en montrant un fragment que vous appelez simplement ft.showou ft.hideen passant respectivement le fragment que vous souhaitez afficher ou masquer.

Pour référence, les définitions d'animation XML utiliseraient la objectAnimatorbalise. Un exemple de slide_in_left pourrait ressembler à ceci:

<?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>
Reto Meier
la source
57
Lorsque j'ai essayé, cela montre RuntimeException: nom d'animateur inconnu: traduire .
Labeeb Panampullan
3
Assurez-vous que les animations définies dans slide_in_left et right sont construites à l'aide d'un ensemble de définitions objectAnimator plutôt que de l'ancienne définition d'animation.
Reto Meier
7
Cela a beaucoup aidé. J'étais sur la bonne voie, mais je n'y suis pas parvenu. Pour les autres lecteurs, vous pouvez également avoir android: interpolator comme attribut, avec votre favori spécifié (tel que "@android: interpolator / linear"). Il s'agit par défaut de "@android: interpolator / accelerate_decelerate".
Dave MacLean
6
Je cible l'API de niveau 7 avec les API de compatibilité. Existe-t-il un moyen pour moi d'animer des fragments?
Jarrod Smith
5
@JarrodSmith, vous pouvez essayer d'utiliser une bibliothèque de compatibilité comme NineOldAndroids pour mettre l'API Honeycomb à Eclair.
M. S
249

Si vous n'êtes pas obligé d'utiliser la bibliothèque de support, jetez un œil à la réponse de Roman .

Mais si vous souhaitez utiliser la bibliothèque de support, vous devez utiliser l'ancien framework d'animation comme décrit ci-dessous.

Après avoir consulté les réponses de Reto et de Blindstuff, j'ai fait fonctionner le code suivant.

Les fragments semblent glisser de la droite et glisser vers la gauche lorsque vous appuyez sur le dos.

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'ordre est important. Cela signifie que vous devez appeler setCustomAnimations()avant replace()ou l'animation ne prendra pas effet!

Ensuite, ces fichiers doivent être placés dans le dossier 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 durée des animations peut être modifiée à n'importe quelle valeur par défaut comme @android:integer/config_shortAnimTimeou tout autre nombre.

Notez que si entre les remplacements de fragments un changement de configuration se produit (par exemple une rotation), l'action de retour n'est pas animée. Il s'agit d'un bogue documenté qui existe toujours dans la version 20 de la bibliothèque de support.

dmanargias
la source
47
Cela m'a sauvé. Attention, la commande est importante , ce qui, naturellement, m'a manqué la première fois. Cela signifie que vous devez appeler setCustomAnimations () avant replace ().
Stephen Kidson
3
J'ai essayé d'implémenter sur mes fragments. J'ai tout écrit comme vous l'avez mentionné mais logcat dit: nom d'animateur inconnu traduire Comment puis-je surmonter ce problème? Au fait, j'appelle mon fragment sur le tiroir de navigation (menu coulissant)
Zafer Celaloglu
Fonctionne très bien mais il s'avère que sa construction avec les outils de génération 21.1 génère une erreur indiquant "Nom de fichier non valide: ne doit contenir que des lettres minuscules et des chiffres ([a-z0-9_.])". Je suggère de modifier les noms de fichiers dans la réponse à pop_enter.xml et pop_exit.xml.
smichak
Excellente solution et cela fonctionne très bien lorsque j'appuie sur le bouton de retour. J'ai juste une question: si je veux créer un backButton personnalisé, quel code dois-je appeler pour reproduire le comportement à partir du bouton de retour?
Thomas Teilmann
1
Thomas si vous voulez sauvegarder, vous devez implémenter ce formulaire: .setCustomAnimations (R.anim.pop_enter, R.anim.pop_exit, R.anim.enter, R.anim.exit)
Alex Zaraos
26

Je vous suggère fortement de l'utiliser au lieu de créer le fichier d'animation car c'est une bien meilleure solution. Android Studio fournit déjà par défaut que animation vous pouvez utiliser sans créer de nouveau fichier XML. Les noms des animations sont android.R.anim.slide_in_left et android.R.anim.slide_out_right et vous pouvez les utiliser comme suit:

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

Production:

entrez la description de l'image ici

Gowthaman M
la source
1
android.R ... "Android Studio fournit une animation par défaut", ce n'est pas pour Android studio, il peut aussi fonctionner dans Eclipse, android.R est spécifique à Android. les choses sur android.R sont différentes sur différents apis.
steve moretz
@stevemoretz thaxs bro J'ai accepté votre point .. Je vais corriger et mettre à jour ma réponse ...
Gowthaman M
5

Ma bibliothèque de support modifiée prend en charge à la fois les animations de vue (ie <translate>, <rotate>) et les animateurs d'objets (ie <objectAnimator>) pour les transitions de fragments. Il est implémenté avec NineOldAndroids . Reportez-vous à ma documentation sur github pour plus de détails.

mark.kedzierski
la source
2

Quant à moi, j'ai besoin de la vue diraction:

dans -> glissez de droite

out -> glisser vers la gauche

Voici le code qui fonctionne pour moi:

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>

code de transaction:

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()
            }
        }
    }
}
Serg Burlaka
la source
Android semble scintiller les transitions avec ces animations (en particulier les traductions)
Gabriel De Oliveira Rohden
@GabrielDeOliveiraRohden quant à moi pas dans toutes les casses
Serg Burlaka
1

Je résous le problème ci-dessous

Animation anim = AnimationUtils.loadAnimation(this, R.anim.slide);
fg.startAnimation(anim);
this.fg.setVisibility(View.VISIBLE); //fg is a View object indicate fragment
Shakawat Hossain
la source