Timeline — conceptos básicos, gestión del tiempo de animación en aplicaciones

Autor: IT Sectr Publicado: 2026-03-02 Tiempo de lectura: 8 min
Timeline (línea de tiempo) es un concepto fundamental de animación que determina cuánto dura una animación, en qué orden se ejecutan sus etapas y cómo el tiempo se traduce en progreso. En el desarrollo de aplicaciones móviles, la línea de tiempo se gestiona mediante duración (duration), retardo (delay), repeticiones (repeat) y marcas de tiempo. En iOS, la línea de tiempo de animación se implementa a través de CACurrentMediaTime y CAMediaTiming, mientras que en Android se usa ValueAnimator y Animator con los parámetros duration, startDelay y repeatCount. Según Apple Documentation, el control preciso de la línea de tiempo es críticamente importante para la sincronización de animaciones: una desincronización de incluso 16 ms (un fotograma a 60fps) es percibida por el usuario como sacudidas. En IT Sectr estandarizamos el uso de la línea de tiempo mediante ValueAnimator en Android y CABasicAnimation con CAMediaTiming en iOS — esto garantiza una gestión uniforme del tiempo en todos los proyectos.

Puntos Clave

  • Timeline — el concepto de gestión del tiempo de animación: duration, delay, repeat, mapeo del tiempo al progreso.
  • CAMediaTiming — protocolo de iOS Core Animation para la gestión de la línea de tiempo: duration, beginTime, repeatCount, speed, timeOffset.
  • ValueAnimator — la clase central de Android para trabajar con la línea de tiempo de animación mediante duration, startDelay, repeatCount.
  • CACurrentMediaTime — función de iOS para obtener el tiempo absoluto en segundos, utilizada para sincronización.
  • TimeInterval — un tipo de datos en iOS (Double) que representa un intervalo de tiempo para cálculos de animación.

¿Qué es Timeline?

Timeline es un modelo de tiempo de animación que define cuándo comienza una animación, cuánto dura y cómo la progresión del tiempo se transforma en cambios del parámetro animado. A diferencia de la animación fotograma a fotograma (frame-by-frame), donde cada fotograma se establece manualmente, la animación con línea de tiempo se describe mediante parámetros: duration — duración total, startDelay — retardo antes del inicio, repeatCount — número de repeticiones, y timingFunction — la curva de velocidad.

La línea de tiempo opera en un espacio normalizado [0, 1] — tiempo local o progreso. El valor cero corresponde al inicio de la animación, el uno a la finalización. Una función de easing (suavizado) convierte el tiempo local lineal en progreso real de la animación. Si repeatCount > 1, la línea de tiempo se cicla (RESTART) o se invierte (REVERSE). En iOS, CAMediaTiming añade speed (velocidad de reproducción, >1 acelera) y timeOffset (desplazamiento de la línea de tiempo). En Android, Animator usa setCurrentPlayTime() para el control directo de la posición en la línea de tiempo. Según Material Design, las animaciones de menos de 100 ms no se perciben como animaciones, mientras que las de más de 500 ms empiezan a irritar. La duración óptima para animaciones de interfaz es de 200–350 ms.

Timeline en iOS: CAMediaTiming y CACurrentMediaTime

En iOS, la gestión de la línea de tiempo de animación se realiza a través del protocolo CAMediaTiming, implementado por CAAnimation y CALayer. Proporciona las propiedades: duration (en segundos), beginTime (tiempo de inicio relativo a la línea de tiempo padre), repeatCount (número de repeticiones), repeatDuration (duración total de repeticiones), autoreverses (reversión automática), fillMode (comportamiento antes/después de la animación), speed (velocidad de reproducción) y timeOffset (desplazamiento de la línea de tiempo).

CACurrentMediaTime() es una función que devuelve el tiempo absoluto en segundos desde el último reinicio del dispositivo. Se utiliza como marca de tiempo base para sincronizar múltiples animaciones: establezca beginTime = CACurrentMediaTime() + offset para iniciar un grupo de animaciones con un retardo preciso. CAMediaTiming también admite la jerarquía de líneas de tiempo — una capa padre puede acelerar/ralentizar todas las animaciones hijas mediante la propiedad speed. En UIKit, UIViewPropertyAnimator (iOS 10+) abstrae la línea de tiempo a través de las propiedades duration, delay y los callbacks startAnimation/pauseAnimation/stopAnimation. En SwiftUI, la estructura Animation proporciona duration como parte de la especificación de la animación, pero el control directo de la línea de tiempo está oculto — para una línea de tiempo personalizada, use TimelineView (iOS 15+) con un scheduler personalizado.

Timeline en Android: Animator y duration

En Android, la gestión de la línea de tiempo está centralizada en la clase Animator y sus subclases (ValueAnimator, ObjectAnimator). Las principales propiedades de la línea de tiempo son: duration (en milisegundos), startDelay (retardo antes del inicio), repeatCount (número de repeticiones), repeatMode (RESTART o REVERSE). El método setCurrentPlayTime(long) permite navegar por la línea de tiempo a cualquier posición arbitraria.

ValueAnimator añade una capa de abstracción: genera valores de 0 a 1 (tiempo normalizado) basados en duration y los pasa a TimeInterpolator. AnimatorSet permite combinar múltiples Animator en una única línea de tiempo con ejecución secuencial (playSequentially) o paralela (playTogether). En Jetpack Compose, la línea de tiempo se gestiona a través de AnimationSpec: tween (durationMillis, delayMillis, easing), spring (dampingRatio, stiffness) y keyframes (puntos en la línea de tiempo con easing personalizado para cada segmento). Compose AnimatedContent usa una línea de tiempo para transitionSpec — el desarrollador describe cómo el contenido aparece/desaparece con desplazamientos temporales. Según Android Performance, la línea de tiempo de animación debe ser múltiplo de 16 ms (ciclo vsync) para 60fps — una duración incorrecta puede causar pérdida de fotogramas debido al desajuste con la tasa de refresco de la pantalla.

Composición de Animaciones en el Tiempo

La línea de tiempo se vuelve especialmente importante al componer múltiples animaciones. Tres patrones básicos: cascada — las animaciones se inician secuencialmente con un desplazamiento (cada siguiente comienza tras un offset de la anterior), paralelo — todas las animaciones comienzan simultáneamente con la misma línea de tiempo, y escalonado (stagger) — las animaciones se inician con superposición (la segunda comienza antes de que termine la primera).

En iOS, la cascada se implementa mediante beginTime de cada CAAnimation = beginTime anterior + duration anterior. Para el escalonado, se usa CAAnimationGroup con diferentes valores de beginTime en las animaciones anidadas. En Android, AnimatorSet admite playSequentially y playTogether; el escalonado se crea estableciendo startDelay para cada Animator. En Compose, AnimatedVisibility con enter/exitTransition usa escalonado en la variante staggerChildren para la aparición en cascada de elementos de lista. En WWDC y Google I/O 2024, ambas plataformas presentaron herramientas de visualización de líneas de tiempo: Xcode Animations Inspector y Android Studio Animations Timeline — muestran la línea de tiempo real y los fotogramas perdidos en tiempo real.

Ejemplos de Código

iOS: CABasicAnimation con CAMediaTiming

Un ejemplo de animación con línea de tiempo personalizada: retardo de 0.3 s, duración de 0.6 s, autoreverse y repetición infinita. CAMediaTiming controla todos los parámetros temporales.

swift
import UIKit

func breathingAnimation(layer: CALayer) {
    let animation = CABasicAnimation(keyPath: "opacity")
    animation.duration = 0.6
    animation.beginTime = CACurrentMediaTime() + 0.3
    animation.fromValue = 1.0
    animation.toValue = 0.3
    animation.autoreverses = true
    animation.repeatCount = .infinity
    animation.speed = 1.0
    animation.fillMode = .both

    layer.add(animation, forKey: "breathing")
}

beginTime = CACurrentMediaTime() + 0.3 proporciona un retardo de 300 ms. autoreverses = true hace que la animación se ejecute en reversa después de cada ciclo. repeatCount = .infinity crea un bucle infinito del efecto “respiración”. speed = 1.0 — velocidad normal; acelere la animación 2x con un valor de 2.0.

iOS: TimelineView para Línea de Tiempo Personalizada

SwiftUI TimelineView (iOS 15+) proporciona acceso a la línea de tiempo del sistema para animaciones personalizadas. La Vista se actualiza en cada tick del scheduler.

swift
import SwiftUI

struct TimelineViewExample: View {
    var body: some View {
        TimelineView(.periodic(from: .now, by: 0.1)) { context in
            let seconds = context.date.timeIntervalSinceReferenceDate
            let phase = sin(seconds * 2 * .pi)

            Circle()
                .fill(Color.blue)
                .frame(width: 60 + 30 * phase)
                .animation(.linear(duration: 0), value: phase)
        }
    }
}

TimelineView con scheduler .periodic genera ticks cada 0.1 s. En el closure, context.date es la hora actual, que se convierte en una fase de onda sinusoidal. El tamaño del círculo pulsa a una frecuencia de 1 Hz. TimelineView es la única forma de crear una animación con su propia línea de tiempo en SwiftUI sin la API de Animation.

Android: ValueAnimator con Línea de Tiempo Personalizada

ValueAnimator con control completo de la línea de tiempo: retardo, duración, repetición. El método setCurrentPlayTime permite saltar a lo largo de la línea de tiempo.

kotlin
import android.animation.ValueAnimator
import android.view.animation.AccelerateDecelerateInterpolator
import android.view.View

fun View.timelineAnimation() {
    ValueAnimator.ofFloat(0f, 1f).apply {
        duration = 400
        startDelay = 200
        repeatCount = 2
        repeatMode = ValueAnimator.REVERSE
        interpolator = AccelerateDecelerateInterpolator()

        addUpdateListener { animator ->
            val progress = animator.animatedFraction
            alpha = progress
            translationX = progress * 100f
        }

        start()
    }
}

startDelay = 200 ms — retardo antes del inicio. repeatMode = REVERSE devuelve la animación al valor inicial. animatedFraction da el progreso de 0 a 1 teniendo en cuenta repeatMode. addUpdateListener se dispara cada fotograma (normalmente 16 ms). Use pause() / resume() para pausar.

Android: AnimatorSet para Composición de Línea de Tiempo

AnimatorSet permite crear líneas de tiempo complejas a partir de múltiples animaciones. El ejemplo demuestra la ejecución secuencial con superposición (stagger).

kotlin
import android.animation.AnimatorSet
import android.animation.ObjectAnimator
import android.view.View

fun View.staggerAnimation() {
    val fadeIn = ObjectAnimator.ofFloat(this, "alpha", 0f, 1f).apply {
        duration = 300
    }
    val slideUp = ObjectAnimator.ofFloat(this, "translationY", 100f, 0f).apply {
        duration = 400
        startDelay = 100
    }
    val scale = ObjectAnimator.ofFloat(this, "scaleX", 0.8f, 1f).apply {
        duration = 250
        startDelay = 200
    }

    AnimatorSet().apply {
        playTogether(fadeIn, slideUp, scale)
        start()
    }
}

playTogether inicia todas las animaciones en paralelo, pero cada una tiene su propio startDelay — esto crea un efecto escalonado: fadeIn comienza primero (0 ms), slideUp después de 100 ms, scale después de 200 ms. La línea de tiempo resultante: 0 — 100 — 200 — 600 ms. Para ejecución secuencial, use playSequentially.

Preguntas Frecuentes

¿En qué se diferencia Animator de ValueAnimator en Android?

Animator es una clase base abstracta para todas las animaciones. ValueAnimator es su subclase que anima valores numéricos sin vincularse a un objeto. ObjectAnimator (subclase de ValueAnimator) anima una propiedad específica de un objeto (por ejemplo, alpha o translationY). Para la línea de tiempo, use ValueAnimator como un temporizador universal con un callback a través de addUpdateListener.

¿Cómo sincronizar animaciones en diferentes dispositivos?

Use relojes del sistema (CACurrentMediaTime en iOS, System.nanoTime en Android) para calcular el progreso, no el número de fotogramas. Para la sincronización en red, use un temporizador basado en NTP con corrección de offset. iOS admite AVAudioSession para la sincronización de la línea de tiempo de audio-vídeo con precisión de milisegundos. Evite la sincronización basada en fotogramas — las frecuencias de fotogramas varían de 30 a 120 fps.

¿Qué son startOffset y repeatCount en Animator?

startOffset es el retardo antes del inicio de la animación en milisegundos. Se utiliza para efectos de cascada y escalonado. repeatCount es el número de repeticiones: 0 = sin repetición, ValueAnimator.INFINITE = bucle infinito. repeatMode determina la dirección: RESTART (reinicio al principio) o REVERSE (dirección inversa). En iOS, startOffset se llama beginTime (en combinación con CACurrentMediaTime), repeatCount es la misma propiedad de CABasicAnimation.

¿Cuál es la duración óptima de la animación?

Material Design recomienda 200–350 ms para animaciones de interfaz. Las animaciones de menos de 100 ms no se perciben como animaciones, mientras que las de más de 500 ms resultan irritantes. Para entrada/salida de elementos: 200–300 ms. Para transiciones entre pantallas: 300–400 ms. Use duraciones más cortas para elementos pequeños (100–200 ms) y más largas para elementos grandes (400–500 ms).

¿Por qué la animación se sacude durante la reproducción?

Las sacudidas (jank) ocurren debido a: operaciones de larga duración en el hilo principal (bloquean el renderizado), jerarquía compleja de View/Layer con overdraw, o uso incorrecto de la línea de tiempo (duración no múltiplo de vsync — 16ms para 60fps, 8ms para 120fps). Use Xcode Instruments Animations o Android Studio Profiler para detectar fotogramas perdidos. En Compose, use Modifier.drawWithCache para almacenar en caché dibujos complejos.

Resumen

  • Timeline es un modelo de tiempo de animación con los parámetros duration, startDelay, repeatCount, repeatMode que definen el flujo de la animación.
  • El protocolo iOS CAMediaTiming gestiona la línea de tiempo mediante duration, beginTime, speed, timeOffset, repeatCount, fillMode.
  • Android Animator y ValueAnimator proporcionan duration, startDelay, repeatCount, repeatMode y setCurrentPlayTime para control directo.
  • AnimatorSet en Android y CAAnimationGroup en iOS permiten combinar animaciones en una única línea de tiempo.
  • TimelineView en SwiftUI (iOS 15+) proporciona acceso al scheduler del sistema para líneas de tiempo personalizadas sin la API de Animation.
  • CACurrentMediaTime() en iOS y System.nanoTime en Android son marcas de tiempo base para la sincronización de animaciones.
  • La duración óptima para animaciones de interfaz es de 200-350 ms según las recomendaciones de Material Design y HIG.

Desarrollaremos una aplicación móvil llave en mano

IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.

Discutir el proyecto

Lea también