Saltar a contenido

Tema 5.4 - Animaciones

Animar es cambiar algo con el tiempo. En Android hay dos formas de hacerlo y la escena 10 de IsmaelAgenda usa las dos a la vez: una secuencia de fotogramas y un cuadrado que gira y escala.

🟢 Leyenda de repaso obligatorio: los textos con este fondo verde son imprescindibles y entran en todas las evaluaciones del módulo.

1. Las dos familias

Por fotogramas Por propiedades
Qué se anima una secuencia de imágenes un valor (giro, escala, color)
Quién dibuja tú, imagen a imagen el sistema, interpolando
Coste crece con el número de imágenes constante
Ejemplo del taller 4 PNG extraídos del vídeo rotación y escala de un cuadrado

Animar por fotogramas es cambiar de imagen; animar por propiedades es cambiar un número y dejar que el sistema interpole.

2. Animación por fotogramas

Los cuatro dibujos salen del vídeo de la unidad, extraídos con ffmpeg:

ffmpeg -ss 0.5 -i video10.mp4 -frames:v 1 -vf scale=320:180 fotograma_05.png
ffmpeg -ss 3   -i video10.mp4 -frames:v 1 -vf scale=320:180 fotograma_3.png
ffmpeg -ss 6   -i video10.mp4 -frames:v 1 -vf scale=320:180 fotograma_6.png
ffmpeg -ss 9   -i video10.mp4 -frames:v 1 -vf scale=320:180 fotograma_9.png

Se copian a res/drawable/ y se recorren con un bucle:

val fotogramas = listOf(
    R.drawable.fotograma_05,                                // los 4 dibujos
    R.drawable.fotograma_3,
    R.drawable.fotograma_6,
    R.drawable.fotograma_9
)
var indice by remember { mutableStateOf(0) }

LaunchedEffect(Unit) {
    while (true) {
        delay(250)                                          // 4 fotogramas por segundo
        indice = (indice + 1) % fotogramas.size              // siguiente, y vuelve al primero
    }
}

Image(painter = painterResource(fotogramas[indice]), contentDescription = "fotograma")
Dato Valor en el taller
fotogramas 4
espera entre fotogramas 250 ms
velocidad resultante 4 fps

El operador % (módulo) hace que la animación vuelva al primer fotograma sola: (indice + 1) % 4 pasa de 3 a 0.

En res/drawable los nombres solo admiten minúsculas, números y guion bajo, y la extensión debe ser .png, .jpg o .webp.

Con delay(250) se consiguen 4 fps. Para 60 fps no se usa delay: se usa withFrameNanos o las animaciones por propiedades.

3. Animación por propiedades

Disparada por un estado: animateFloatAsState

var grande by remember { mutableStateOf(false) }            // estado normal
val escala by animateFloatAsState(                          // valor animado
    targetValue = if (grande) 1.6f else 1f,                 // a dónde va
    label = "escala"
)

Box(
    Modifier
        .size(80.dp)
        .graphicsLayer { scaleX = escala; scaleY = escala } // escala sin recolocar
)

Continua: rememberInfiniteTransition

val transicion = rememberInfiniteTransition(label = "giro")
val giro by transicion.animateFloat(
    initialValue = 0f,
    targetValue = 360f,                                     // una vuelta completa
    animationSpec = infiniteRepeatable(tween(2000, easing = LinearEasing)),
    label = "angulo"
)

animateFloatAsState anima hacia un valor cuando cambia el estado; rememberInfiniteTransition anima sin parar, sin que nadie cambie nada.

graphicsLayer rota y escala en la fase de dibujo: no vuelve a medir ni a colocar la vista, así que es barato.

4. Las dos animaciones a la vez

La escena 10 mide lo que ocurre y lo enseña en pantalla:

Medida Antes de pulsar Después de pulsar «Ampliar»
fotograma 1 de 4 4 de 4
cambios de fotograma 40 71
rotación 134° 122°
escala 1.0 1.6

La rotación no para nunca (transición infinita) y por eso baja de 134° a 122°: ha dado la vuelta. La escala solo cambia cuando se pulsa el botón.

Una animación infinita no se detiene al cambiar otro estado: sigue girando mientras la pantalla exista. Por eso los grados suben y bajan.

5. Así se ve funcionando

Con el cuadrado ampliado (escala 1.6) y un fotograma de la secuencia:

Animación con escala ampliada

Un instante después: otro fotograma y otra rotación, con la misma escala.

Animación con otro fotograma

Comparando las dos capturas se ve lo importante: el fotograma cambia solo (animación por fotogramas) y la rotación también, mientras la escala se queda donde la dejó el botón.

6. Alternativa: animaciones ya hechas (Lottie)

Ventaja Inconveniente
las diseña un diseñador en After Effects hay que añadir una dependencia
ficheros JSON pequeños no se controla el detalle fino
misma animación en Android, iOS y web pesa si el JSON es grande

Lottie sirve para animaciones complejas ya diseñadas; para un giro o una escala, las animaciones de Compose son más simples y no añaden dependencias.

7. Lo que tienes que llevarte de este apartado

  • Dos familias: por fotogramas (cambiar imágenes) y por propiedades (interpolar valores).
  • (indice + 1) % tamaño hace el bucle de fotogramas.
  • delay(250) = 4 fps; para 60 fps no se usa delay.
  • animateFloatAsState responde a un estado; rememberInfiniteTransition no para nunca.
  • graphicsLayer rota y escala sin volver a medir la vista.
  • Medido: escala 1.0 → 1.6 y rotación que sigue girando entre capturas.

Bibliografía y documentación oficial

Presentación