Las animaciones son un punto fundamental hoy en día para dar presencia al momento de cargar datos, imágenes transición entre pantallas etc, y es un punto fundamental para los "android developers" y no hacer tan "aburridas" las interfaces; realizar animaciones como la siguiente, en la cual variamos la traslación en el eje de las Y y la opacidad de cero a uno:
O está en la cual variamos solo la translación en el eje de las X:
O está en la cual variamos solo la opacidad:
Es realmente fácil e inclusive las podemos ejecutar de manera paralela en un mismo elemento o recurso de una vista.
Uno de los grandes principios del Material Design es el uso de las animaciones como elemento fundamental para interactuar con el usuario mediante la UI dependiendo de la interactividad que realice el usuario con la aplicación.
Para las animaciones en Android que a la final son sencillas transiciones entre un estado y otro, vamos a hacer uso de los ObjectAnimator
que proveen funcionalidades para animar vistas mediante un target u objetivo que viene siendo definido con los PropertyValuesHolder
que son la forma en la que indicamos la propiedad y los valores que queremos animar...
Por ejemplo, la propiedad que queremos animar podría ser la opacidad y el valor de cero como valor inicial y el de uno para que quede completamente visible; entonces pasamos de un estado en la cual la vista se encuentra invisible a completamente visible (por supuesto, puede ser a la inversa o quedarnos en un punto medio y que sean semi visibles, etc).
Tipos de animaciones en Android: Animaciones mediante ObjectAnimator
Ya teniendo claro el marco teórico, que en resumen es definir la propiedad y los valores asociados, ahora veremos cuáles tipos de animaciones podemos hacer, es decir, que podemos animar y cuáles podrían ser sus valores.
Animando con la opacidad con PropertyValuesHolder
Podemos definir si queremos que las animaciones afecten la opacidad; por ejemplo si quisiéramos indicar que la vista pase de completamente oculta a visible debemos usar la propiedad ALPHA
con valores flotantes entre cero y uno; el código en Kotlin sería:
PropertyValuesHolder.ofFloat(View.ALPHA, 0f, 1f))
O si queremos que la transición sea de de visible a oculta:
PropertyValuesHolder.ofFloat(View.ALPHA, 1f, 0f))
Animando con las rotaciones con PropertyValuesHolder
Para rotar las vistas podemos hacerlo en los ejes X y/o Y mediante las propiedades ROTATION_X
y ROTATION_Y
respectivamente; para rotar en el eje de las X 45 grados el código en Kotlin sería:
PropertyValuesHolder.ofFloat(View.ROTATION_X, 0f, 45f))
Para rotar 45 grados en el eje de las Y:
PropertyValuesHolder.ofFloat(View.ROTATION_Y, 0f, 45f))
En los ejemplo anteriores indicamos que queremos rotar desde los cero grados hasta los 45 grados (va de 0 a 360 grados).
En general, las rotaciones en las vistas no sería muy útiles a menos que quieras realizar algo muy específico.
Animando con los escalado con PropertyValuesHolder
Otra forma de realizar animaciones es con el escalado de las vistas en uno de los ejes X y Y cuyos valores van de cero para completamente oculta y a uno para el tamaño original, para escalar en el eje de las X el código en Kotlin es el siguiente:
ObjectAnimator.ofPropertyValuesHolder(bottomLay,
PropertyValuesHolder.ofFloat(View.SCALE_X,
0f, 1f))
Para el eje de las Y empleamos la propiedad SCALE_Y
.
Animando con las traslaciones con PropertyValuesHolder:
Esta vista es muy útil cuando queremos realizar el efecto de entrada o salida como el de la imagen que mostramos en un inicio; para ello es recomendable que cuando sea de salida o entrada emplear el tamaño total de la vista, es decir, si la animación que queremos desarrollar es la de salida en el eje de las Y, entonces significa que la vista se está mostrando (no existe traslación, o la traslación en el eje de las Y es de cero) y el próximo estado, es la ocultación total de la vista; para ello debemos trasladar la vista hacia el fondo empleando el total del tamaño de la vista para ocultarlo hacia abajo:
Ocultar hacia abajo (Hide Bottom) animación
En base a lo explicado anteriormente tenemos:
PropertyValuesHolder.ofFloat(View.TRANSLATION_Y, 0f, hi.toFloat())
Ocultar hacia arriba (Hide Top) animación
Podemos jugar con los signos (positivo y negativo) para variar la translación de abajo hacia arriba o de arriba hacia abajo:
PropertyValuesHolder.ofFloat(View.TRANSLATION_Y, 0f, -hi.toFloat())
Ocultar hacia los lados(derecha izquierda) animación
Siguiendo con las translaciones en Android, para ocultar/mostrar hacia los lados, es decir de derecha a izquierda o izquierda a derecha, debemos emplear la propiedad View.TRANSLATION_X
en vez de la de View.TRANSLATION_Y
y en vez de emplear el algo de la vista, empleamos el ancho:
val wi = view.width
val iconAnim = ObjectAnimator.ofPropertyValuesHolder(view,
PropertyValuesHolder.ofFloat(View.TRANSLATION_X, 0f, wi.toFloat()),
Finalmente un código de ejemplo base que podemos adaptar a cualquiera de los ejemplos que vimos anteriormente quedaría así con Kotlin:
val hi = view.height
view.visibility = View.VISIBLE
val iconAnim = ObjectAnimator.ofPropertyValuesHolder(view,
PropertyValuesHolder.ofFloat(View.TRANSLATION_Y, hi.toFloat(), 0f))
iconAnim.duration = VIEW_ANIMATION
iconAnim.start()
Múltiples propiedades para realizar una animación más compleja en Android
Un punto muy importante es que podemos emplear uno o más propiedades para realizar las animaciones, es decir, podemos emplear uno dos o tres propiedades para la opacidad, o una opacidad y una traslación o como lo queramos configurar; para ello es el siguiente código en Kotlin que muestra cómo realizar una traslación en el eje de las Y junto con la opacidad:
val hi = view.height
view.visibility = View.VISIBLE
val iconAnim = ObjectAnimator.ofPropertyValuesHolder(view,
PropertyValuesHolder.ofFloat(View.TRANSLATION_Y, hi.toFloat(), 0f),
PropertyValuesHolder.ofFloat(View.ALPHA, 0f, 1f))
iconAnim.duration = VIEW_ANIMATION
iconAnim.start()
El código en Java quedaría de la siguiente forma:
view.setVisibility(View.VISIBLE);
Animator iconAnim = ObjectAnimator.ofPropertyValuesHolder(view,
PropertyValuesHolder.ofFloat(View.TRANSLATION_Y, 0f, -
view.getHeight()),
PropertyValuesHolder.ofFloat(View.ALPHA, 1f, 0f));
iconAnim.setDuration(VIEW_ANIMATION);
iconAnim.start();
Animaciones en Java y métodos/propiedades para el tiempo
Con Java no hay mucho más que decir, vemos que es un poco más de código, se emplean algunos métodos en vez de propiedades, pero por lo demás es el mismo funcionamiento y misma lógica; y esto se debe a que son muy parecidos ambos lenguajes de programación; al final tenemos el método setDuration()
en Java o propiedad duration
en Kotlin, que permite definir el tiempo en milisegundos que durará la animación:
val VIEW_ANIMATION: Long = 300
Y finalmente el método start()
para iniciar la animación; existe un métodostartDelay
en Kotlin y en Java el método setStartDelay()
para indicar el delay o retraso de la animación, esto es muy útil si realizamos varias animaciones al mismo tiempo.
Listener para controlar los estados de las animaciones
Con los listener podemos saber cuando empieza una animación, cuando termina, si se repite o se cancela la misma y realizar alguna acción en consecuencia; por ejemplo, en el caso de las traslaciones para ocultar la vista mediante el desplazamiento o traslado de la misma ya sea en el eje de las X o de las Y, es un buen consejo ocultar la vista View.GONE
una vez terminada la animación; para eso podemos emplear el método onAnimationEnd
, de igual manera, para cuando comience la animación y la vista se encuentre oculta, podemos indicar en el método onAnimationStart
que la vista sea visible otra vez para iniciar la animación View.VISIBLE
; finalmente, el código en Kotlin quedaría:
iconAnim.addListener(object : Animator.AnimatorListener {
override fun onAnimationStart(animation: Animator) {
}
override fun onAnimationEnd(animation: Animator) {
}
override fun onAnimationCancel(animation: Animator) {
}
override fun onAnimationRepeat(animation: Animator) {
}
});
Y en Java tenemos:
iconAnim.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
bottomLay.setVisibility(View.VISIBLE);
}
@Override
public void onAnimationEnd(Animator animation) {
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
En dónde iconAnim
es una instancia de la clase ObjectAnimator
que vimos en los ejemplos anteriores.
Tipos de animaciones en Android: Animaciones mediante Drawable
Otro tipo de efectos de transición o animaciones muy comunes son las empleadas mediante los recursos Drawable que a al final definen un XML con atributos y tags y a posterior se le ata a un elemento de la vista para definir el comportamiento de la animación.
Animaciones de vistas o de recursos (tween animation)
Este tipo de animaciones permite variar la posición, tamaño, rotación y opacidad/transparencia de un elemento de una vista; son ideales para ejecutar al inicio de una pantalla o cuando el usuario realiza alguna interacción sobre el contenido de la vista, como un click o algo similar; también son ideales para cambiar de estatus elementos de las vistas al terminar algún proceso.
Podemos modificar lo siguiente:
- Duración Cuánto tiempo va a durar la animación.
- Delay
- Interpolación de tiempo Propiedades que se cambiarán en función del tiempo.
Entre algunas otras propiedades, pero estas son las más importantes; finalmente, para obtener una animación como la que vemos al final de esta sección, tenemos que conocer la siguiente información y de esta forma entender como trabaja.
Empleamos el siguiente recurso que lo tenemos registrado en:
res/anim/animacion.xml
El nombre animacion.xml
es el nombre del recurso, puedes colocar el que quieras pero el mismo debe estar contenido dentro de res/anim/
.
<set>: Contenedor padre de la animación
Un contenedor que contiene los elementos a animar (<alpha>
, <alpha>
, <scale>
, <translate>
y <rotate>
) que contiene los siguientes atributos:
- android:interpolatorEs la interpolación que vamos a aplicar en la animación.
- android:shareInterpolatorSi es
true
se aplicará la misma interpolación a todos los hijos del elemento. - android:shareInterpolatorSi es
true
se aplicará la misma interpolación a todos los hijos del elemento.
<alpha>: Propiedad para la opacidad de las animaciones
Esta es una propiedad que permite definir el valor de opacidad del elemento en la animación, para eso contamos con un par de atributos:
android:fromAlpha
: es un valor flotante que va de 0.0 para completamente invisible a 1.0 que es completamente visible; el valor medio es transparente amayo o menor grado.android:toAlpha
: es un valor flotante que va de 0.0 para completamente visible a 1.0 que es completamente invisible; el valor medio es transparente amayo o menor grado.
<scale>: Propiedad para la escala de las animaciones
Esta potente propiedad permite hacer el resizing o redimensiones de los elementos en la animación; para eso emplea un par de pivotes para que especifiques a partir de donde va a empezar el reescalado de la imagen pivotX
y pivotY
; por ejemplo si el valor tomado por estos pivotes es de 0, 0 respectivamente (arriba a la izquierda del elemento a animar) la animación empezará desde la parte de arriba a la derecha a reescalar; cuenta con los siguientes atributos:
android:fromXScale
: 1.0 significa que no se va a reescalar en el eje de las X, otro valor indica que se redimensiona la imagen; es el valor en el cual se comenzará a reescalar.android:toXScale
: 1.0 significa que no se va a reescalar en el eje de las X, otro valor indica que se redimensiona la imagen; es el valor en el cual se terminará de reescalar.android:fromYScale
: 1.0 significa que no se va a reescalar en el eje de las Y, otro valor indica que se redimensiona la imagen; es el valor en el cual se comenzará a reescalar.android:toYScale
: 1.0 significa que no se va a reescalar en el eje de las Y, otro valor indica que se redimensiona la imagen; es el valor en el cual se terminará de reescalar.android:pivotX
: Permite especificar la coordenada X desde donde se va a empezar a reescalar.android:pivotY
: Permite especificar la coordenada Y desde donde se va a empezar a reescalar.
<translate>: Propiedad de las traslaciones de las animaciones
Esta propiedad también es muy útil, y permite realizar traslaciones entre los ejes X y Y, su funcionamiento es muy similar al del escalado, pero con el enfoque a las traslaciones; los valores van desde -100 a 100 por ciento (es decir, son porcentajes relativos al mismo elemento a animar si el valor es "%" y si el valor es "%p" indica que el valor relativo es al padre o elemento contenedor del elemento a animar); sus atributos son:
android:fromXDelta
: Valor relativo al elemento a animar ("%") o al elemento padre ("%p") indica en porcentajes la traslación inicial en el eje X.android:toXDelta
: Valor relativo al elemento a animar ("%") o al elemento padre ("%p") indica en porcentajes la traslación final en el eje X.android:fromYDelta
: Valor relativo al elemento a animar ("%") o al elemento padre ("%p") indica en porcentajes la traslación inicial en el eje Y.android:toYDelta
: Valor relativo al elemento a animar ("%") o al elemento padre ("%p") indica en porcentajes la traslación final en el eje Y.
<rotate> Propiedad para las rotaciones de las animaciones
Permite realizar rotaciones; sus atributos son:
android:fromDegrees
: Valor flotante que indica la posición de inicio en grados.android:toDegrees
: Valor flotante que indica la rotación final en grados.android:pivotX
: Al igual que ocurre con el escalado, este valor nos indica la posición X desde donde se ejecutará la rotación; puede ser relativo al elemento a animar ("%") o a su padre ("%p")Y.android:pivotY
: Al igual que ocurre con el escalado, este valor nos indica la posición Y donde se ejecutará la rotación; puede ser relativo al elemento a animar ("%") o a su padre ("%p")Y.
Finalmente ya con esto claro, presentamos la siguiente animación:
El recurso que empleamos es:
<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale
android:duration="2000"
android:fromXScale="3.0"
android:fromYScale="2.0"
android:toXScale="1.0"
android:toYScale="1.0" />
<rotate
android:startOffset="2000"
android:duration="2000"
android:fromDegrees="0"
android:toDegrees="360"
android:pivotX="50%"
android:pivotY="50%"/>
<translate
android:startOffset="4000"
android:duration="2000"
android:fromXDelta="0"
android:fromYDelta="0"
android:toXDelta="60"
android:toYDelta="100" />
<alpha
android:startOffset="4000"
android:duration="2000"
android:fromAlpha="1"
android:toAlpha="0" />
</set>
Luego el código en Kotlin sería:
AnimationUtils.loadAnimation(this, R.anim.animacion).also {
hyperspaceJumpAnimation ->
findViewById<TextView>(R.id.text_view).startAnimation(hyperspaceJumpAnimation)
}
Y en Java sería:
ImageView spaceshipImage = (ImageView) findViewById(R.id.spaceshipImage);
Animation hyperspaceJumpAnimation = AnimationUtils.loadAnimation(this, R.anim.hyperspace_jump);
spaceshipImage.startAnimation(hyperspaceJumpAnimation);
Por supuesto, debes de reemplazar el tipo de elemento y nombre del mismo por el tuyo que desees animar.
Conclusión
En esta entrada vimos como realizar sencillas transiciones o animaciones que son ideales para mostrar u ocultar elementos en una pantalla, pero esto va mucho más allá nos falta conversar como realizar transiciones entre pantalla (al darle click a un botón se muestre la conversión del botón en la nueva pantalla), como animar listados o los RecyclerView entre muchas otras cosas más que iremos viendo en próximas entregas.
Desarrollo con Laravel, Django, Flask, CodeIgniter, HTML5, CSS3, MySQL, JavaScript, Vue, Android, iOS, Flutter