Animar la transición entre fragmentos

284

Estoy tratando de animar la transición entre fragmentos. Recibí la respuesta de los siguientes
Fragmentos y animación de 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();

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

Pero cuando probé esto, mostró

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)

¿Algunas ideas? Cuando revisé la referencia de Honeycomb API translateestá allí. ¿Qué me perdí?
¿Hay alguna otra forma de animar la transición entre fragmentos? Gracias

Labeeb Panampullan
fuente
use ANIMATOR --- no animación! use android.R.ANIMATOR.fade_in funciona, NO use android.R.ANIM.fade_in - tiene
errores de

Respuestas:

347

Debe usar el nuevo android.animationmarco (animadores de objetos) con FragmentTransaction.setCustomAnimationsy también FragmentTransaction.setTransition.

Aquí hay un ejemplo sobre el uso setCustomAnimationsde FragmentHideShow.java de ApiDemos :

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

y aquí está el XML animador relevante 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" />

Tenga en cuenta que puede combinar varios animadores utilizando <set>, como lo haría con el marco de animación anterior.


EDITAR : Dado que la gente pregunta acerca de deslizar hacia adentro / deslizarse, comentaré sobre eso aquí.

Slide-in y slide-out

Puede animar, por supuesto, los translationX, translationY, x, y ypropiedades, pero en general se desliza involucrar a la animación de contenido hacia y desde fuera de la pantalla. Hasta donde sé, no hay propiedades de transición que usen valores relativos. Sin embargo, esto no le impide escribirlos usted mismo. Recuerde que las animaciones de propiedades simplemente requieren métodos getter y setter en los objetos que está animando (en este caso, las vistas), por lo que puede crear sus propios métodos getXFractiony setXFractionmétodos en su subclase de vista, de esta manera:

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

Ahora puede animar la propiedad 'xFraction', así:

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

Tenga en cuenta que si el objeto en el que está animando no tiene el mismo ancho que su padre, las cosas no se verán del todo bien, por lo que es posible que deba ajustar la implementación de su propiedad para adaptarla a su caso de uso.

Nurik romano
fuente
8
Obtuve el fade_in y fade_out para trabajar, pero los otros en / res / animator dan errores. Y ninguno de ellos parece ser para entrar y salir. Intenté escribir mis propios xml para hacer esto, pero todo lo que termino son fragmentos encima de fragmentos. ¿Un poco más de ayuda por favor?
Dave MacLean
¿Y qué hay de la traducción? ¿Cómo se hace una traducción con valores en porcentaje en un objeto que el animador define en XML, por favor? No tuve éxito en animar AdapterViewFlipper durante el volteo con animaciones de diapositivas verticales definidas en xml ...
GBouerat
66
Estoy obteniendo 11-19 10: 27: 50.912: W / PropertyValuesHolder (23107): Método setXFraction () con tipo float no encontrado en la clase de clase de destino android.widget.FrameLayout. Pero en mi XML tengo mi vista personalizada MyFrameLayout. ¿Algunas ideas?
Barkside
13
En realidad, Roman, el consejo también debería ser al revés: al usar la Biblioteca de soporte, debe usar el antiguo marco de animación (android.R.anim) con FragmentTransaction.setCustomAnimations ao
pjv
1
@RomanNurik esta respuesta funcionó muy bien en la mayoría de los dispositivos, pero para algunos usuarios (específicamente en algunos teléfonos Samsung Galaxy S3 / 4) el ancho no se informó durante las animaciones por alguna razón, lo que provocó que el fragmento nunca apareciera. Pude hacer que funcione para aquellos usuarios que usan un OnPredrawListener como se muestra aquí: mavyasoni9891.blogspot.com/2014/06/…
ajpolt
188

He hecho de esta manera:

Agregue este método para reemplazar fragmentos con animaciones :

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

Debe agregar cuatro animaciones en la carpeta anim que está asociada con el recurso :

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>

Salida:

ingrese la descripción de la imagen aquí

Está hecho .

Hiren Patel
fuente
14
Gran solución Sin embargo, no estoy seguro de por qué cambiaste las instrucciones a RTL. Mi método:.setCustomAnimations(R.anim.enter_from_right, R.anim.exit_to_left, R.anim.enter_from_left, R.anim.exit_to_right)
zeta del
2
Impresionante solución. Un enfoque similar y los mismos archivos de animación funcionan para las transiciones entre actividades.
Stan
1
@MikeZriel, res -> anim -> pon tu xml aquí
Hiren Patel
3
Gracias Hiren, cambio la velocidad (700) a (300) mucho mejor y más como iOS
Mike Zriel
3
LOL, volví con solución. Estaba importando android.app.fragment y FragmentManager en cada clase de Java. Después de verificar algunos materiales, descubrí que usar 'setCustomAnimations ()' necesita que se importe la biblioteca android.support.v4. Es importante decir que debería ser 'support.v4.app'! Reemplacé todos los métodos 'getFragmentManager ()' con 'getSupportFragmentManager ()', y todos los importados 'android.app.Fragment / FragmentManager ...' a 'android.support.v4.app ....', luego esto la animación comenzó a funcionar bien sin bloquearse ... Si ustedes están atrapados en casos similares, lea mi solución. Thx Hiren Patel xD
KoreanXcodeWorker
58

Si puede permitirse atarse solo a Lollipop y más tarde, esto parece ser el truco:

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

Espero que esto ayude.

scorpiodawg
fuente
1
Si bien eso lo logrará en Lollipop, no es práctico ya que el porcentaje de dispositivos que ejecutan Lollipop es insignificante (actualmente el 1.6% de los dispositivos Android ejecutan Lollipop).
Eran Goldin
1
new Slide(...): la llamada requiere API nivel 21
Chintan Soni
¿Qué significa getKey ()?
Alvaro
13
@EranGoldin Nada dura para siempre ... ¿te burlarías de una solución única para Android 2.0+ hoy?
Tom
@Tom tienes un punto. Sin embargo, cuando su aplicación tiene una gran base de usuarios, no puede simplemente aumentar el nivel de API. Si la mayoría de sus usuarios ya no podrán ejecutar su aplicación después, esa no es la solución.
Eran Goldin
47

La respuesta de Nurik fue muy útil, pero no pude hacer que funcionara hasta que encontré esto . En resumen, si está utilizando la biblioteca de compatibilidad (por ejemplo, SupportFragmentManager en lugar de FragmentManager), la sintaxis de los archivos de animación XML será diferente.

extraño
fuente
28

Aquí hay una animación de entrada / salida de diapositivas entre fragmentos:

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

Estamos usando un objectAnimator.

Aquí están los dos archivos xml en la subcarpeta del animador .

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>

Espero que eso ayude a alguien.

kirilv
fuente
37
mover la vista para 2000 px, es una solución muy fea.
carlo.marinangeli
44
El exit_anim simplemente "aparece" fuera de la pantalla para mí, no se anima de nuevo en la pantalla. ¿Algunas ideas? Estoy usando.setCustomAnimations(R.animator.slide_in_left, R.animator.slide_out_right, R.animator.slide_in_left, R.animator.slide_out_right)
Mr Pablo
@ MrPablo, la razón es que probablemente no haya copiado el código anterior. Se debe llamar a setCustomAnimations antes del método de reemplazo.
Galya
En este caso, si reemplazo otro fragmento con animación y minimizo la aplicación inmediatamente antes del tiempo de espera de la animación o la duración una y otra vez vuelvo a la aplicación, mostrará el fragmento anterior y el fragmento actual en paralelo.
Príncipe
23

Para cualquier otra persona que quede atrapada, asegúrese de llamar a setCustomAnimations antes de la llamada para reemplazar / agregar al crear la transacción.

Charlie
fuente
12

La implementación de Android SDK de FragmentTransaction quiere un Animatortiempo mientras que la biblioteca de soporte quiere un Animation, no me pregunten por qué, pero después del comentario de strangeluk busqué en el código de Android 4.0.3 y la biblioteca de soporte. Usos del SDK de Android loadAnimator()y usos de la biblioteca de soporteloadAnimation()

Sherpya
fuente
7

Intente usar esta solución simple y en ayunas. Android proporciona algunos animations predeterminados .

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

Salida:

ingrese la descripción de la imagen aquí

Gowthaman M
fuente
¡Guau ... esta debería ser la respuesta aceptada! Una solución simple y elegante. Es muy suave en comparación con las otras respuestas
sugeridas