Criar uma animação de transição personalizada

Uma transição personalizada permite que você crie uma animação que não está disponível em nenhuma das classes de transição integradas. Por exemplo, você pode definir uma transição personalizada que transforma em cinza a cor de primeiro plano do texto e dos campos de entrada para indicar que os campos estão desativados na nova tela. Esse tipo de alteração ajuda os usuários a ver os campos que você desativou.

Uma transição personalizada, como um dos tipos de transição integrados, aplica animações a visualizações filhas das cenas inicial e final. Entretanto, diferentemente dos tipos de transição integrados, você precisa fornecer o código que captura valores de propriedade e gera animações. Você também pode definir um subconjunto de visualizações de destino para sua animação.

Esta página ensina a capturar valores de propriedade e gerar animações para criar transições personalizadas.

Estender a classe Transition

Para criar uma transição personalizada, adicione uma classe ao seu projeto que estende a classe Transition e modifica as funções mostradas no snippet a seguir:

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) {}
    }
    

As seções a seguir explicam como modificar essas funções.

Capturar valores de propriedade da visualização

As animações de transição usam o sistema descrito em Animação de propriedade. As animações de propriedade alteram uma propriedade de visualização entre um valor inicial e final durante um período especificado. Portanto, o framework precisa ter o valor inicial e final da propriedade para construir a animação.

No entanto, uma animação de propriedade geralmente precisa apenas de um pequeno subconjunto de todos os valores de propriedade da visualização. Por exemplo, uma animação de cor precisa de valores de propriedade de cor, enquanto uma animação de movimento precisa de valores de propriedade de posição. Como os valores de propriedade necessários para uma animação são específicos de uma transição, o framework de transições não fornece todos os valores de propriedade para uma transição. Em vez disso, o framework invoca funções de retorno de chamada que permitem que uma transição capture apenas os valores de propriedade necessários e armazene-os no framework.

Capturar valores iniciais

Para transmitir os valores iniciais de visualização para o framework, implemente a função captureStartValues(transitionValues). O framework chama essa função para todas as visualizações na cena inicial. O argumento da função é um objeto TransitionValues que contém uma referência à visualização e uma instância Map em que é possível armazenar os valores de visualização desejados. Na implementação, recupere esses valores de propriedade e transmita-os para o framework armazenando-os no mapa.

Para garantir que a chave para um valor de propriedade não entre em conflito com outras chaves TransitionValues, use o seguinte esquema de nomenclatura:

    package_name:transition_name:property_name
    

O snippet a seguir mostra uma implementação da função 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());
        }
        ...
    }
    

Capturar valores finais

O framework chama a função captureEndValues(TransitionValues) uma vez para cada visualização de destino na cena final. Em todos os outros aspectos, captureEndValues() funciona da mesma forma que captureStartValues().

O snippet de código a seguir mostra uma implementação da função captureEndValues():

Kotlin

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

Java

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

Neste exemplo, as funções captureStartValues() e captureEndValues() invocam captureValues() para recuperar e armazenar valores. A propriedade de visualização recuperada por captureValues() é a mesma, mas tem valores diferentes nas cenas inicial e final. O framework mantém mapas separados para os estados inicial e final de uma visualização.

Criar um animador personalizado

Para animar as mudanças em uma visualização entre o estado na cena inicial e na cena final, forneça um animador modificando a função createAnimator(). Quando o framework chama essa função, ele transmite a visualização raiz da cena e os objetos TransitionValues que contêm os valores inicial e final capturados.

O número de vezes que o framework chama a função createAnimator() depende das mudanças que ocorrem entre as cenas inicial e final. Por exemplo, considere uma animação de esmaecimento/exibição gradual implementada como uma transição personalizada. Se a cena inicial tiver cinco destinos e dois deles forem removidos da cena final, e a cena final tiver três destinos da cena inicial mais um novo destino, o framework chamará createAnimator() seis vezes: três chamadas animam o esmaecimento e a exibição gradual dos destinos que permanecem em ambos os objetos da cena. Mais duas chamadas animam o esmaecimento dos destinos removidos da cena final e uma chamada anima a exibição gradual do novo destino na cena final.

Para visualizações de destino que existem nas cenas inicial e final, o framework fornece um objeto TransitionValues para os argumentos startValues e endValues. Para visualizações de destino que só existem na cena inicial ou final, o framework fornece um objeto TransitionValues para o argumento correspondente e null para o outro.

Para implementar a função createAnimator(ViewGroup, TransitionValues, TransitionValues) ao criar uma transição personalizada, use os valores de propriedade de visualização capturados para criar um objeto Animator e retorná-lo ao framework. Para um exemplo de implementação, consulte a classe ChangeColor no exemplo CustomTransition (link em inglês). Para mais informações sobre os animadores de propriedade, consulte Animação de propriedade.

Aplicar uma transição personalizada

As transições personalizadas funcionam da mesma forma que as transições integradas. Você pode aplicar uma transição personalizada usando um gerenciador de transição, conforme descrito em Aplicar uma transição.