Mover visualização com animação

Os objetos na tela geralmente precisam ser reposicionados devido à interação ou processamento do usuário em segundo plano. Em vez de atualizar imediatamente a posição do objeto, o que faz com que ele pisque de uma área para outra, use uma animação para mover o objeto da posição inicial para a final.

Uma maneira de o Android permitir reposicionar os objetos de visualização na tela é usando ObjectAnimator. Você informa a posição final em que quer que o objeto fique, bem como a duração da animação. Também é possível usar interpoladores de tempo para controlar a aceleração ou desaceleração da animação.

Alterar a posição da visualização com o ObjectAnimator

A API ObjectAnimator oferece uma maneira de mudar as propriedades de uma visualização com uma duração específica. Ela contém métodos estáticos para criar instâncias do ObjectAnimator, dependendo do tipo de atributo que você está animando. Ao reposicionar suas visualizações na tela, use os atributos translationX e translationY.

Confira um exemplo de uma ObjectAnimator que move a visualização para uma posição a 100 pixels da esquerda da tela em 2 segundos:

Kotlin

ObjectAnimator.ofFloat(view, "translationX", 100f).apply {
    duration = 2000
    start()
}

Java

ObjectAnimator animation = ObjectAnimator.ofFloat(view, "translationX", 100f);
animation.setDuration(2000);
animation.start();

Este exemplo usa o método ObjectAnimator.ofFloat(), porque os valores de translação precisam ser flutuantes. O primeiro parâmetro é a visualização que você quer animar. O segundo parâmetro é a propriedade que você está animando. Como a visualização precisa se mover horizontalmente, a propriedade translationX é usada. O último parâmetro é o valor final da animação. Nesse exemplo, o valor de 100 indica uma posição com muitos pixels da esquerda da tela.

O próximo método especifica quanto tempo a animação leva, em milissegundos. Neste exemplo, a animação é executada por 2 segundos (2.000 milissegundos).

O último método faz com que a animação seja executada, o que atualiza a posição da visualização na tela.

Para saber mais sobre como usar ObjectAnimator, consulte Animar usando o ObjectAnimator.

Adicionar movimento curvo

Embora o uso do ObjectAnimator seja conveniente, por padrão, ele reposiciona a visualização ao longo de uma linha reta entre os pontos inicial e final. O Material Design depende de curvas para o movimento espacial de objetos na tela e do tempo de uma animação. O uso de movimentos curvos dá ao app uma sensação mais material e torna as animações mais interessantes.

Definir seu próprio caminho

A classe ObjectAnimator tem construtores que permitem animar coordenadas usando duas ou mais propriedades simultaneamente com um caminho. Por exemplo, o animador abaixo usa um objeto Path para animar as propriedades X e Y de uma visualização:

Kotlin

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    val path = Path().apply {
        arcTo(0f, 0f, 1000f, 1000f, 270f, -180f, true)
    }
    val animator = ObjectAnimator.ofFloat(view, View.X, View.Y, path).apply {
        duration = 2000
        start()
    }
} else {
    // Create animator without using curved path
}

Java

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
  Path path = new Path();
  path.arcTo(0f, 0f, 1000f, 1000f, 270f, -180f, true);
  ObjectAnimator animator = ObjectAnimator.ofFloat(view, View.X, View.Y, path);
  animator.setDuration(2000);
  animator.start();
} else {
  // Create animator without using curved path
}

Veja a aparência da animação em arco:

Figura 1. Uma animação de caminho em curva.

Um Interpolator é uma implementação de uma curva de easing. Consulte a documentação do Material Design para saber mais sobre o conceito de curvas de easing. Uma Interpolator define como valores específicos em uma animação são calculados como uma função de tempo. O sistema fornece recursos XML para as três curvas básicas na especificação do Material Design:

  • @interpolator/fast_out_linear_in.xml
  • @interpolator/fast_out_slow_in.xml
  • @interpolator/linear_out_slow_in.xml

Usar o PathInterpolator

A classe PathInterpolator é um interpolador introduzido no Android 5.0 (nível 21 da API). Ela é baseada em uma curva de Bézier ou em um objeto Path. Os exemplos do Android na documentação do Material Design para easing usam PathInterpolator.

PathInterpolator tem construtores baseados em diferentes tipos de curvas de Bézier. Todas as curvas de Bézier têm pontos de início e término fixados em (0,0) e (1,1), respectivamente. Os outros argumentos do construtor dependem do tipo de curva de Bézier que está sendo criado.

Por exemplo, para uma curva quadrática de Bézier, apenas as coordenadas X e Y de um ponto de controle são necessárias:

Kotlin

val myInterpolator = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    PathInterpolator(0.67f, 0.33f)
} else {
    LinearInterpolator()
}

Java

Interpolator myInterpolator = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
  myInterpolator = new PathInterpolator(0.67f, 0.33f);
} else {
  myInterpolator = new LinearInterpolator();
}

Isso produz uma curva de easing que começa rapidamente e desacelera à medida que se aproxima do fim.

O construtor cúbico de Bézier tem pontos de início e término fixos de maneira semelhante, mas exige dois pontos de controle:

Kotlin

val myInterpolator = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    PathInterpolator(0.5f, 0.7f, 0.1f, 1.0f)
} else {
    LinearInterpolator()
}

Java

Interpolator myInterpolator = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
  myInterpolator = new PathInterpolator(0.5f, 0.7f, 0.1f, 1.0f);
} else {
  myInterpolator = new LinearInterpolator();
}

Essa é uma implementação da curva de easing de aceleração enfatizada (link em inglês) do Material Design.

Para ter mais controle, uma Path arbitrária pode ser usada para definir a curva:

Kotlin

val myInterpolator = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
  val path = Path().apply {
    moveTo(0.0f, 0.0f)
    cubicTo(0.5f, 0.7f, 0.1f, 1.0f, 1.0f, 1.0f)
  }
  PathInterpolator(path)
} else {
  LinearInterpolator()
}

Java

Interpolator myInterpolator = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
  Path path = new Path();
  path.moveTo(0.0f, 0.0f);
  path.cubicTo(0.5f, 0.7f, 0.1f, 1.0f, 1.0f, 1.0f);
  myInterpolator = new PathInterpolator(path);
} else {
  myInterpolator = new LinearInterpolator();
}

Isso produz a mesma curva de easing do exemplo de Bézier cúbico, mas com o uso de um Path.

Você também pode definir um interpolador de caminho como um recurso XML:

<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
    android:controlX1="0.5"
    android:controlY1="0.7"
    android:controlX2="0.1f"
    android:controlY2="1.0f"/>

Depois de criar um objeto PathInterpolator, você pode transmiti-lo para o método Animator.setInterpolator(). O Animator usa o interpolador para determinar a curva de tempo ou de caminho quando é iniciado.

Kotlin

val animation = ObjectAnimator.ofFloat(view, "translationX", 100f).apply {
    interpolator = myInterpolator
    start()
}

Java

ObjectAnimator animation = ObjectAnimator.ofFloat(view, "translationX", 100f);
animation.setInterpolator(myInterpolator);
animation.start();