Fragmentos y animación de Android

265

¿Cómo debe implementar el tipo de deslizamiento que, por ejemplo, utiliza el cliente Honeycomb Gmail?

Puede TransactionManagermanejar esto automáticamente agregando y eliminando los Fragmentos, es un poco difícil probar esto debido a que el emulador es una presentación de diapositivas :)

alexanderblom
fuente

Respuestas:

388

Para animar la transición entre fragmentos, o para animar el proceso de mostrar u ocultar un fragmento, utiliza el Fragment Managerpara crear un Fragment Transaction.

Dentro de cada Fragmento de transacción, puede especificar animaciones de entrada y salida que se usarán para mostrar y ocultar respectivamente (o ambas cuando se usa reemplazar).

El siguiente código muestra cómo reemplazaría un fragmento deslizando un fragmento y deslizando el otro en su lugar.

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

Para lograr lo mismo ocultando o mostrando un fragmento que simplemente llamarías ft.showo ft.hide, pasando el Fragmento que deseas mostrar u ocultar respectivamente.

Como referencia, las definiciones de animación XML usarían la objectAnimatoretiqueta. Un ejemplo de slide_in_left podría verse así:

<?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
fuente
57
Cuando probé esto, muestra RuntimeException: nombre de animador desconocido: traducir .
Labeeb Panampullan
3
Asegúrese de que las animaciones definidas en slide_in_left y right se construyan utilizando un conjunto de definiciones de objectAnimator en lugar de la antigua definición de animación.
Reto Meier
77
Eso ayudó mucho. Estaba en el camino correcto, pero no llegué hasta allí. Para los demás lectores, también podría tener android: interpolator como un atributo, con su favorito especificado (como "@android: interpolator / linear"). El valor predeterminado es "@android: interpolator / accelerate_decelerate".
Dave MacLean
66
Estoy apuntando al API Nivel 7 con las API de compatibilidad. ¿Hay alguna manera de animar Fragments?
Jarrod Smith
55
@JarrodSmith puede intentar usar una biblioteca de compatibilidad como NineOldAndroids para llevar la API Honeycomb a Eclair.
Sr. S
249

Si no tiene que usar la biblioteca de soporte, eche un vistazo a la respuesta de Roman .

Pero si desea usar la biblioteca de soporte , debe usar el antiguo marco de animación como se describe a continuación.

Después de consultar las respuestas de Reto y de blindstuff, he conseguido que funcione el siguiente código.

Los fragmentos aparecen deslizándose desde la derecha y deslizándose hacia la izquierda cuando se presiona hacia atrás.

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

El orden es importante. ¡Esto significa que debe llamar setCustomAnimations()antes replace()o la animación no tendrá efecto!

A continuación, estos archivos deben colocarse dentro de la carpeta 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 duración de las animaciones se puede cambiar a cualquiera de los valores predeterminados como @android:integer/config_shortAnimTimeo cualquier otro número.

Tenga en cuenta que si entre reemplazos de fragmentos se produce un cambio de configuración (por ejemplo, rotación), la acción de retroceso no se anima. Este es un error documentado que todavía existe en la versión 20 de la biblioteca de soporte.

dmanargias
fuente
47
Esto solo me salvó. Tenga en cuenta que prestar atención al pedido es importante , lo que, naturalmente, me perdí la primera vez. Esto significa que debe llamar a setCustomAnimations () antes de reemplazar ().
Stephen Kidson
3
Traté de implementarlo en mis fragmentos. Escribí todo lo que mencionaste pero logcat dice: traductor desconocido del nombre del animador ¿Cómo puedo solucionar este problema? Por cierto, estoy llamando a mi fragmento en el cajón de navegación (menú deslizante)
Zafer Celaloglu
Funciona muy bien, pero resulta que construir esto con las herramientas de construcción 21.1 genera un error que dice "Nombre de archivo no válido: debe contener solo letras minúsculas y dígitos ([a-z0-9_.])". Sugiero editar los nombres de archivo en la respuesta a pop_enter.xml y pop_exit.xml.
smichak
Gran solución y funciona muy bien cuando presiono el botón Atrás. Solo tengo una pregunta: si quiero crear un backButton personalizado, ¿a qué código debo llamar para replicar el comportamiento desde el botón Atrás?
Thomas Teilmann
1
Thomas, si quieres retroceder, debes implementar este formulario: .setCustomAnimations (R.anim.pop_enter, R.anim.pop_exit, R.anim.enter, R.anim.exit)
Alex Zaraos
26

Le recomiendo que use esto en lugar de crear el archivo de animación porque es una solución mucho mejor. Android Studio ya proporciona valores predeterminados animation que puede usar sin crear ningún archivo XML nuevo. Los nombres de las animaciones son android.R.anim.slide_in_left y android.R.anim.slide_out_right y puede usarlos de la siguiente manera:

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
1
android.R ... "Android Studio proporciona animación predeterminada", eso no es para Android Studio, también puede funcionar en eclipse, android.R es específico de Android. Y, por cierto, no compartió la información de qué apis tiene esto. cosas en android.R son diferentes en diferentes apis.
Steve Moretz
@stevemoretz thaxs bro Acepté tu punto ... Corregiré y actualizaré mi respuesta ...
Gowthaman M
5

Mi biblioteca de soporte modificada admite el uso de animaciones de visualización (es decir <translate>, <rotate>) y animadores de objetos (es decir <objectAnimator>) para las transiciones de fragmentos. Se implementa con NineOldAndroids . Consulte mi documentación en github para más detalles.

mark.kedzierski
fuente
2

En cuanto a mí, necesito la vista diraction:

en -> deslizar desde la derecha

fuera -> deslizar hacia la izquierda

Aquí funciona para mí el código:

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>

codigo de transacción:

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
fuente
Android parece estar parpadeando las transiciones con esas animaciones (especialmente las traducidas)
Gabriel De Oliveira Rohden
@GabrielDeOliveiraRohden en cuanto a mí, no en todos los casos
Serg Burlaka
1

Resuelvo esto de la siguiente manera

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
fuente