Animer la transition entre les fragments

284

J'essaie d'animer la transition entre les fragments. J'ai obtenu la réponse des fragments et de l'animation Android suivants

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

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

Mais quand j'ai essayé cela a montré

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)

Des idées? Lorsque j'ai vérifié la référence API Honeycomb translateest là. Qu'est-ce que j'ai raté?
Existe-t-il un autre moyen d'animer la transition entre les fragments? Je vous remercie

Labeeb Panampullan
la source
utilisez ANIMATOR --- pas Animation! utiliser android.R.ANIMATOR.fade_in fonctionne, NE PAS utiliser android.R.ANIM.fade_in - il a un comportement
BUGS

Réponses:

348

Vous devez utiliser le nouveau android.animationframework (animateurs d'objets) avec FragmentTransaction.setCustomAnimationsainsi que FragmentTransaction.setTransition.

Voici un exemple d'utilisation setCustomAnimationsde FragmentHideShow.java d'ApiDemos :

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

et voici le XML d'animateur pertinent de 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" />

Notez que vous pouvez combiner plusieurs animateurs en utilisant <set>, tout comme vous le pouviez avec l'ancien framework d'animation.


EDIT : Étant donné que les gens posent des questions sur les entrées / sorties, je vais en parler ici.

Slide-in et slide-out

Vous pouvez d'animer les cours translationX, translationY, xet les ypropriétés, mais généralement diapositives impliquent l' animation du contenu depuis et hors écran. Pour autant que je sache, il n'y a pas de propriétés de transition qui utilisent des valeurs relatives. Cependant, cela ne vous empêche pas de les écrire vous-même. N'oubliez pas que les animations de propriétés nécessitent simplement des méthodes getter et setter sur les objets que vous animez (dans ce cas, les vues), vous pouvez donc simplement créer vos propres méthodes getXFractionet setXFractionméthodes sur votre sous-classe de vue, comme ceci:

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

Vous pouvez maintenant animer la propriété 'xFraction', comme ceci:

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

Notez que si l'objet dans lequel vous animez n'est pas de la même largeur que son parent, les choses ne sembleront pas tout à fait correctes, vous devrez donc peut-être modifier votre implémentation de propriété en fonction de votre cas d'utilisation.

Roman Nurik
la source
8
J'ai fait fonctionner fade_in et fade_out, mais les autres dans / res / animator donnent des erreurs. Et aucun de ceux-ci ne semble même être destiné à entrer et à sortir. J'ai essayé d'écrire mes propres fichiers XML pour ce faire, mais je ne me retrouve qu'avec des fragments par-dessus des fragments. Un peu d'aide s'il vous plaît?
Dave MacLean
Et la traduction? Comment faites-vous une traduction avec des valeurs en pourcentage dans un objectAnimator défini en XML, s'il vous plaît? Je n'ai pas réussi à animer AdapterViewFlipper lors du retournement avec des animations de diapositives verticales à définir en xml ...
GBouerat
6
Je reçois 11-19 10: 27: 50.912: W / PropertyValuesHolder (23107): Méthode setXFraction () avec le type float introuvable sur la classe de classe cible android.widget.FrameLayout. Mais dans mon XML, j'ai ma vue personnalisée MyFrameLayout. Des idées?
bord de la mer
13
En fait, Roman, les conseils devraient également aller dans le sens inverse: lorsque vous utilisez la bibliothèque de support, vous devez utiliser l'ancien framework d'animation (android.R.anim) avec FragmentTransaction.setCustomAnimations ao
pjv
1
@RomanNurik, cette réponse fonctionnait très bien sur la plupart des appareils, mais pour certains utilisateurs (en particulier sur certains téléphones Samsung Galaxy S3 / 4), la largeur n'était pas signalée pendant les animations pour une raison quelconque, ce qui faisait que le fragment n'apparaissait jamais. J'ai pu le faire fonctionner pour les utilisateurs utilisant un OnPredrawListener comme indiqué ici: mavyasoni9891.blogspot.com/2014/06/…
ajpolt
188

J'ai fait comme ça:

Ajoutez cette méthode pour remplacer des fragments par des animations :

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

Vous devez ajouter quatre animations dans le dossier anim qui est associé à la 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>

Production:

entrez la description de l'image ici

C'est fait .

Hiren Patel
la source
14
Excellente solution. Cependant, je ne sais pas pourquoi vous avez échangé les instructions vers RTL. Ma méthode:.setCustomAnimations(R.anim.enter_from_right, R.anim.exit_to_left, R.anim.enter_from_left, R.anim.exit_to_right)
zed
2
Super solution. Une approche similaire et les mêmes fichiers d'animation fonctionnent pour les transitions entre les activités.
Stan
1
@MikeZriel, res -> anim -> mettez votre xml ici
Hiren Patel
3
Merci Hiren, je change la vitesse (700) en (300) beaucoup mieux et plus comme iOS
Mike Zriel
3
LOL, je suis revenu avec une solution. J'importais android.app.fragment et FragmentManager sur chaque classe java. Après avoir vérifié certains matériaux, j'ai constaté que l'utilisation de 'setCustomAnimations ()' nécessite l'importation de la bibliothèque android.support.v4. important de dire que ça devrait être 'support.v4.app'! J'ai remplacé toutes les méthodes 'getFragmentManager ()' par 'getSupportFragmentManager ()', et toutes les importations 'android.app.Fragment / FragmentManager ...' vers 'android.support.v4.app ....', puis ceci l'animation a commencé à bien fonctionner sans crash ... Si vous êtes coincés dans des cas similaires, lisez ma solution. Thx Hiren Patel xD
KoreanXcodeWorker
58

Si vous pouvez vous permettre de vous attacher uniquement à Lollipop et plus tard, cela semble faire l'affaire:

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

J'espère que cela t'aides.

scorpiodawg
la source
1
Bien que cela puisse le faire sur Lollipop, ce n'est pas pratique car le pourcentage d'appareils exécutant Lollipop est négligeable (actuellement 1,6% des appareils Android exécutent Lollipop).
Eran Goldin
1
new Slide(...): l'appel nécessite le niveau 21 de l'API
Chintan Soni
que signifie getKey ()?
Alvaro
13
@EranGoldin Rien ne dure éternellement .. vous moqueriez-vous d'une seule solution Android 2.0+ aujourd'hui?
Tom
@Tom vous avez raison. Cependant, lorsque votre application a une grande base d'utilisateurs, vous ne pouvez pas simplement augmenter le niveau de l'API. Si la plupart de vos utilisateurs ne pourront plus exécuter votre application après, ce n'est pas du tout une solution.
Eran Goldin
47

La réponse de Nurik a été très utile, mais je n'ai pas pu le faire fonctionner jusqu'à ce que je trouve cela . En bref, si vous utilisez la bibliothèque de compatibilité (par exemple SupportFragmentManager au lieu de FragmentManager), la syntaxe des fichiers d'animation XML sera différente.

strangeluck
la source
28

Voici une animation de diapositive d'entrée / sortie entre les fragments:

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

Nous utilisons un objectAnimator.

Voici les deux fichiers xml du sous-dossier de l' animateur .

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>

J'espère que cela aiderait quelqu'un.

kirilv
la source
37
déplacer la vue pour 2000 px, est une solution très moche.
carlo.marinangeli
4
Le exit_anim "saute" simplement de l'écran pour moi, il ne s'anime pas en retour sur l'écran. Des idées? J'utilise.setCustomAnimations(R.animator.slide_in_left, R.animator.slide_out_right, R.animator.slide_in_left, R.animator.slide_out_right)
M. Pablo
@MrPablo, la raison est probablement que vous n'avez pas copié le code ci-dessus. setCustomAnimations doit être appelé avant la méthode replace.
Galya
Dans ce cas, si je remplace un autre fragment par une animation et que je minimise l'application immédiatement avant l'expiration ou la durée de l'animation et que je reviens à l'application, elle affichera le fragment précédent et le fragment actuel en parallèle.
Prince
23

Pour toute autre personne interceptée, assurez-vous que setCustomAnimations est appelé avant l'appel pour remplacer / ajouter lors de la génération de la transaction.

Charlie
la source
12

La mise en œuvre du SDK Android de FragmentTransaction veut un Animatorcertain temps, la bibliothèque de support en veut un Animation, ne me demandez pas pourquoi, mais après le commentaire de strangeluk, j'ai examiné le code Android 4.0.3 et la bibliothèque de support. Utilisations du SDK Android loadAnimator()et utilisations de la bibliothèque de supportloadAnimation()

sherpya
la source
7

Essayez d'utiliser cette solution simple et rapide. Android fournit certains animations par défaut .

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
Woow .. ce devrait être la réponse acceptée !! Une solution simple et élégante. C'est très lisse par rapport aux autres suggestions de réponses
Chathura Buddhika