Cómo mover una vista con animación

A menudo, los objetos en pantalla deben cambiarse de posición debido a la interacción o el procesamiento del usuario en segundo plano. En lugar de actualizar inmediatamente la posición del objeto, que hace que parpadee de un área a otra, usa una animación para moverlo desde la posición inicial hasta su posición final.

Una forma en que Android te permite cambiar la posición de tus objetos de vista en la pantalla es con ObjectAnimator. Debes proporcionar la posición final en la que deseas que se establezca el objeto y la duración de la animación. También puedes usar interpoladores de tiempo para controlar la aceleración o desaceleración de la animación.

Cómo cambiar la posición de la vista con ObjectAnimator

La API de ObjectAnimator proporciona una manera de cambiar las propiedades de una vista con una duración específica. Contiene métodos estáticos para crear instancias de ObjectAnimator, según el tipo de atributo que estás animando. Cuando reposiciones tus vistas en la pantalla, usa los atributos translationX y translationY.

A continuación, se muestra un ejemplo de un objeto ObjectAnimator que mueve la vista a una posición 100 píxeles desde la izquierda de la pantalla en 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();

En este ejemplo, se usa el método ObjectAnimator.ofFloat(), ya que los valores de traducción deben ser flotantes. El primer parámetro es la vista que quieres animar. El segundo parámetro es la propiedad que estás animando. Como la vista debe moverse horizontalmente, se usa la propiedad translationX. El último parámetro es el valor final de la animación. En este ejemplo, el valor de 100 indica una posición a muchos píxeles desde la izquierda de la pantalla.

El siguiente método especifica cuánto tarda la animación en milisegundos. En este ejemplo, la animación se ejecuta durante 2 segundos (2,000 milisegundos).

El último método hace que se ejecute la animación, lo que actualiza la posición de la vista en la pantalla.

Para obtener más información sobre el uso de ObjectAnimator, consulta Cómo animar con ObjectAnimator.

Cómo agregar movimientos curvos

Si bien resulta conveniente usar ObjectAnimator, de forma predeterminada, reposiciona la vista en una línea recta entre los puntos de inicio y finalización. Material Design se basa en curvas para el movimiento espacial de objetos en la pantalla y el tiempo de una animación. El uso de movimientos curvos le da a tu app una sensación más material y hace que tus animaciones sean más interesantes.

Cómo definir tu propia trayectoria

La clase ObjectAnimator tiene constructores que te permiten animar las coordenadas usando dos o más propiedades a la vez junto con una ruta. Por ejemplo, el siguiente animador usa un objeto Path para animar las propiedades X e Y de una vista:

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
}

La animación de arco se ve de la siguiente manera:

Figura 1: Una animación de ruta curva.

Un Interpolator es una implementación de una curva de aceleración. Consulta la documentación de Material Design para obtener más información sobre el concepto de curvas de aceleración. Un Interpolator define cómo se calculan los valores específicos de una animación en función del tiempo. El sistema proporciona recursos XML para las tres curvas básicas en la especificación de Material Design:

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

Cómo usar PathInterpolator

La clase PathInterpolator es un interpolador que se introdujo en Android 5.0 (nivel de API 21). Se basa en una curva Bézier o un objeto Path. En los ejemplos de Android que se incluyen en la documentación de Material Design para acelerar, se usa PathInterpolator.

PathInterpolator tiene constructores basados en diferentes tipos de curvas Bézier. Todas las curvas Bézier tienen puntos de inicio y finalización fijos en (0,0) y (1,1), respectivamente. Los otros argumentos del constructor dependen del tipo de curva Bézier que se cree.

Por ejemplo, para una curva Bézier cuadrática, solo se necesitan las coordenadas X e Y de un punto de control:

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

Esto produce una curva de aceleración que comienza rápido y se desacelera a medida que se acerca al final.

De manera similar, el constructor cúbico Bézier tiene puntos de inicio y finalización fijos, pero requiere dos puntos de control:

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

Esta es una implementación de la curva de aceleración de enfatización de desaceleración de Material Design.

Para obtener un mayor control, se puede usar un Path arbitrario para definir la 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();
}

Esto produce la misma curva de aceleración que el ejemplo cúbico de Bézier, pero usa un Path en su lugar.

También puedes definir un interpolador para la trayectoria como un 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"/>

Una vez que creas un objeto PathInterpolator, puedes pasarlo al método Animator.setInterpolator(). Animator usa el interpolador para determinar el tiempo o la curva de la ruta cuando se inicia.

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