Crea una animación de transición personalizada

Una transición personalizada permite crear una animación que no está disponible en ninguna de las clases de transición integradas. Por ejemplo, puedes definir una transición personalizada que cambie el color en primer plano de los campos de texto y entrada a gris para indicar que los campos están inhabilitados en la pantalla nueva. Este tipo de cambio ayuda a los usuarios a ver los campos que inhabilitaste.

Una transición personalizada, al igual que uno de los tipos de transición integradas, aplica animaciones a las vistas secundarias de las escenas inicial y final. Sin embargo, a diferencia de los tipos de transición integrados, debes proporcionar el código que captura los valores de propiedad y genera animaciones. Quizás también debas definir un subconjunto de vistas objetivo para la animación.

En esta página, se detalla cómo capturar valores de propiedad y generar animaciones para crear transiciones personalizadas.

Extiende la clase de transición

Para crear una transición personalizada, agrega una clase al proyecto que extienda la clase Transition y anule las funciones que se muestran en el siguiente fragmento:

Kotlin

    class CustomTransition : Transition() {

        override fun captureStartValues(transitionValues: TransitionValues) {}

        override fun captureEndValues(transitionValues: TransitionValues) {}

        override fun createAnimator(
            sceneRoot: ViewGroup,
            startValues: TransitionValues?,
            endValues: TransitionValues?
        ): Animator? {}

    }
    

Java

    public class CustomTransition extends Transition {

        @Override
        public void captureStartValues(TransitionValues values) {}

        @Override
        public void captureEndValues(TransitionValues values) {}

        @Override
        public Animator createAnimator(ViewGroup sceneRoot,
                                       TransitionValues startValues,
                                       TransitionValues endValues) {}
    }
    

En las siguientes secciones, se explica cómo anular estas funciones.

Captura valores de propiedades de vista

Las animaciones de transición utilizan el sistema de animación de propiedades que se describe en Animación de propiedades. Las animaciones de propiedades cambian una propiedad de vista entre un valor inicial y uno final durante un período específico, por lo que el marco de trabajo debe tener el valor inicial y el final de la propiedad para crear la animación.

Sin embargo, una animación de propiedad suele requerir solo un pequeño subconjunto de todos los valores de propiedad de la vista. Por ejemplo, una animación de color requiere valores de propiedad de color, mientras que una animación de movimiento requiere valores de propiedad de posición. Como los valores de propiedad necesarios para una animación son específicos de una transición, el marco de trabajo de transiciones no proporciona todos los valores de propiedad para una transición. En cambio, el marco de trabajo invoca funciones de devolución de llamada que permiten que una transición capture solo los valores de propiedad que necesita y los almacene en el marco de trabajo.

Captura valores iniciales

Para pasar los valores de vista inicial al marco de trabajo, implementa la función captureStartValues(transitionValues). El marco de trabajo llama a esta función para cada vista en la escena inicial. El argumento de la función es un objeto TransitionValues que contiene una referencia a la vista y una instancia Map en la que puedes almacenar los valores de vista que desees. En tu implementación, recupera esos valores de propiedad y pásalos de nuevo al marco de trabajo almacenándolos en el mapa.

Para garantizar que la clave para un valor de propiedad no entre en conflicto con otras claves de TransitionValues, usa el siguiente esquema de nombres:

    package_name:transition_name:property_name
    

En el siguiente fragmento, se muestra una implementación de la función captureStartValues():

Kotlin

    class CustomTransition : Transition() {

        // Define a key for storing a property value in
        // TransitionValues.values with the syntax
        // package_name:transition_class:property_name to avoid collisions
        private val PROPNAME_BACKGROUND = "com.example.android.customtransition:CustomTransition:background"

        override fun captureStartValues(transitionValues: TransitionValues) {
            // Call the convenience method captureValues
            captureValues(transitionValues)
        }

        // For the view in transitionValues.view, get the values you
        // want and put them in transitionValues.values
        private fun captureValues(transitionValues: TransitionValues) {
            // Get a reference to the view
            val view = transitionValues.view
            // Store its background property in the values map
            transitionValues.values[PROPNAME_BACKGROUND] = view.background
        }

        ...

    }
    

Java

    public class CustomTransition extends Transition {

        // Define a key for storing a property value in
        // TransitionValues.values with the syntax
        // package_name:transition_class:property_name to avoid collisions
        private static final String PROPNAME_BACKGROUND =
                "com.example.android.customtransition:CustomTransition:background";

        @Override
        public void captureStartValues(TransitionValues transitionValues) {
            // Call the convenience method captureValues
            captureValues(transitionValues);
        }

        // For the view in transitionValues.view, get the values you
        // want and put them in transitionValues.values
        private void captureValues(TransitionValues transitionValues) {
            // Get a reference to the view
            View view = transitionValues.view;
            // Store its background property in the values map
            transitionValues.values.put(PROPNAME_BACKGROUND, view.getBackground());
        }
        ...
    }
    

Captura valores finales

El marco de trabajo llama a la función captureEndValues(TransitionValues) una vez para cada vista objetivo en la escena final. En los demás aspectos, captureEndValues() funciona igual que captureStartValues().

En el siguiente fragmento de código, se muestra una implementación de la función captureEndValues():

Kotlin

    override fun captureEndValues(transitionValues: TransitionValues) {
        captureValues(transitionValues)
    }
    

Java

    @Override
    public void captureEndValues(TransitionValues transitionValues) {
        captureValues(transitionValues);
    }
    

En este ejemplo, las funciones captureStartValues() y captureEndValues() invocan captureValues() para recuperar y almacenar valores. La propiedad de vista que recupera captureValues() es la misma, pero tiene valores diferentes en las escenas inicial y final. El marco de trabajo mantiene mapas separados para los estados inicial y final de una vista.

Crea un animador personalizado

Para animar los cambios en una vista entre su estado en la escena inicial y su estado en la escena final, debes proporcionar un animador anulando la función createAnimator(). Cuando el marco de trabajo llama a esta función, pasa a la vista raíz de la escena y a los objetos TransitionValues que contienen los valores iniciales y finales que capturaste.

La cantidad de veces que el marco de trabajo llama a la función createAnimator() depende de los cambios que hay entre las escenas inicial y final. Por ejemplo, considera una animación de fundido de salida/entrada implementada como una transición personalizada. Si la escena inicial tiene cinco objetivos de los cuales se quitan dos de la escena final, y la escena final tiene los tres objetivos de la escena inicial más un objetivo nuevo, el marco de trabajo llama a createAnimator() seis veces: tres animan el fundido de entrada y salida de los objetivos que permanecen en ambos objetos de escena, otras dos llamadas animan el fundido de salida de los objetivos que se quitan de la escena final, y una llamada anima el fundido de entrada del nuevo objetivo en la escena final.

Para las vistas objetivo que existen en las escenas inicial y final, el marco de trabajo proporciona un objeto TransitionValues para los argumentos startValues y endValues. En cuanto a las vistas objetivo que solo existen en la escena inicial o final, el marco de trabajo proporciona un objeto TransitionValues para el argumento correspondiente y null para el otro.

Para implementar la función createAnimator(ViewGroup, TransitionValues, TransitionValues) cuando creas una transición personalizada, usa los valores de propiedad de vista que capturaste a fin de crear un objeto Animator y devolverlo al marco de trabajo. Para una implementación de ejemplo, consulta la clase ChangeColor en el ejemplo CustomTransition. Si quieres obtener más información sobre los animadores de propiedades, consulta Animación de propiedades.

Aplica una transición personalizada

Las transiciones personalizadas funcionan igual que las transiciones integradas. Puedes aplicar una transición personalizada con un administrador de transiciones, como se describe en Aplica una transición.