Animar gráficos drawable

Em algumas situações, as imagens precisam ser animadas na tela. Isso será útil se você quiser exibir uma animação de carregamento personalizada composta por várias imagens ou se quiser que um ícone se transforme em outro depois de uma ação do usuário. O Android oferece algumas opções para animações de drawables.

A primeira opção é usar uma AnimationDrawable. Isso permite especificar vários arquivos drawable estáticos que serão exibidos um por vez para criar uma animação. A segunda opção é usar uma AnimatedVectorDrawable, que permite animar as propriedades de um drawable vetorial.

Usar AnimationDrawable

Uma forma de animar Drawables é carregar uma série de recursos drawable, um por vez, para criar uma animação. Essa é uma animação tradicional porque é criada com uma sequência de imagens diferentes que são exibidas em ordem, como um rolo de filme. A classe AnimationDrawable é a base para animações drawable.

Embora seja possível definir os frames de uma animação no código por meio da API da classe AnimationDrawable, é mais fácil executá-la com um único XML file que lista os frames que compõem a animação. O XML file desse tipo de animação pertence ao diretório res/drawable/ do projeto Android. Nesse caso, as instruções são a ordem e a duração de cada frame da animação.

O XML file consiste em um elemento <animation-list> como o nó raiz e em uma série de nós <item> filhos que definem individualmente um frame: um recurso drawable para o frame e a duração dele. Veja um exemplo de XML file para uma animação drawable:

    <animation-list xmlns:android="http://schemas.android.com/apk/res/android"
        android:oneshot="true">
        <item android:drawable="@drawable/rocket_thrust1" android:duration="200" />
        <item android:drawable="@drawable/rocket_thrust2" android:duration="200" />
        <item android:drawable="@drawable/rocket_thrust3" android:duration="200" />
    </animation-list>
    

Esta animação é executada por apenas três frames. Ao definir o atributo android:oneshot da lista como verdadeiro, ele passará pelo ciclo apenas uma vez, depois será interrompido e mantido no último frame. Se ele for definido como falso, a animação será executada repetidamente. Com esse XML salvo como rocket_thrust.xml no diretório res/drawable/ do projeto, é possível adicioná-lo como imagem de plano de fundo a uma visualização e depois chamá-lo para exibição. Veja um exemplo de atividade em que a animação é adicionada a ImageView e animada ao tocar a tela:

Kotlin

    private lateinit var rocketAnimation: AnimationDrawable

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.main)

        val rocketImage = findViewById<ImageView>(R.id.rocket_image).apply {
            setBackgroundResource(R.drawable.rocket_thrust)
            rocketAnimation = background as AnimationDrawable
        }

        rocketImage.setOnClickListener({ rocketAnimation.start() })
    }
    

Java

    AnimationDrawable rocketAnimation;

    public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.main);

      ImageView rocketImage = (ImageView) findViewById(R.id.rocket_image);
      rocketImage.setBackgroundResource(R.drawable.rocket_thrust);
      rocketAnimation = (AnimationDrawable) rocketImage.getBackground();

      rocketImage.setOnClickListener(new View.OnClickListener() {
          @Override
          public void onClick(View view) {
            rocketAnimation.start();
          }
      });
    }
    

É importante observar que o método start() chamado no AnimationDrawable não pode ser chamado durante o método onCreate() da atividade, porque AnimationDrawable ainda não está totalmente anexado à janela. Se você quiser exibir a animação imediatamente, sem exigir interação, chame-o a partir do método onStart() na sua atividade, que será chamada quando o Android tornar a visualização visível na tela.

Para mais informações sobre a sintaxe XML, tags e atributos disponíveis, consulte Recursos de animação.

Usar AnimatedVectorDrawable

Um drawable vetorial é um tipo de drawable que pode ser escalonado sem ficar pixelado ou desfocado. A classe AnimatedVectorDrawable (e AnimatedVectorDrawableCompat para compatibilidade com versões anteriores) permite animar as propriedades de um drawable vetorial, como rotacioná-lo ou mudar os dados do caminho para transformá-lo em uma imagem diferente.

Em geral, os drawables vetoriais animados são definidos em três XML files:

  • Um drawable vetorial com o elemento <vector> em res/drawable/
  • Um drawable vetorial animado com o elemento <animated-vector> em res/drawable/
  • Um ou mais animadores de objeto com o elemento <objectAnimator> em res/animator/

Drawables vetoriais animados podem animar os atributos dos elementos <group> e <path>. Os elementos <group> definem um conjunto de caminhos ou subgrupos, e o elemento <path> define os caminhos a serem desenhados.

Ao definir um drawable vetorial que você quer animar, use o atributo android:name para dar um nome exclusivo a grupos e caminhos. Assim, você poderá consultá-los a partir das definições do animador. Por exemplo:

res/drawable/vectordrawable.xml

    <vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:height="64dp"
        android:width="64dp"
        android:viewportHeight="600"
        android:viewportWidth="600">
        <group
            android:name="rotationGroup"
            android:pivotX="300.0"
            android:pivotY="300.0"
            android:rotation="45.0" >
            <path
                android:name="v"
                android:fillColor="#000000"
                android:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z" />
        </group>
    </vector>
    

A definição de drawable vetorial animado se refere aos grupos e caminhos no drawable vetorial pelos nomes deles:

res/drawable/animatorvectordrawable.xml

    <animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
      android:drawable="@drawable/vectordrawable" >
        <target
            android:name="rotationGroup"
            android:animation="@animator/rotation" />
        <target
            android:name="v"
            android:animation="@animator/path_morph" />
    </animated-vector>
    

As definições de animação representam objetos ObjectAnimator ou AnimatorSet. O primeiro animador neste exemplo rotaciona o grupo de destino em 360 graus:

res/animator/rotation.xml

    <objectAnimator
        android:duration="6000"
        android:propertyName="rotation"
        android:valueFrom="0"
        android:valueTo="360" />
    

O segundo animador neste exemplo transforma o caminho do drawable vetorial de uma forma em outra. Ambos os caminhos precisam ser compatíveis com a transformação: eles precisam ter o mesmo número de comandos e o mesmo número de parâmetros para cada comando.

res/animator/path_morph.xml

    <set xmlns:android="http://schemas.android.com/apk/res/android">
        <objectAnimator
            android:duration="3000"
            android:propertyName="pathData"
            android:valueFrom="M300,70 l 0,-70 70,70 0,0   -70,70z"
            android:valueTo="M300,70 l 0,-70 70,0  0,140 -70,0 z"
            android:valueType="pathType" />
    </set>
    

Veja o AnimatedVectorDrawable resultante:

Para mais informações, consulte a referência de API para AnimatedVectorDrawable.