Timeline — basics, animation timing management in applications

Author: IT Sectr Published: 2026-03-02 Reading time: 8 min
Timeline is a fundamental animation concept that determines how long an animation lasts, in what order its stages execute, and how time maps to progress. In mobile app development, the timeline is managed through duration, delay, repeat, and timestamps. In iOS, the animation timeline is implemented via CACurrentMediaTime and CAMediaTiming, while in Android it uses ValueAnimator and Animator with duration, startDelay, and repeatCount parameters. According to Apple Documentation, precise timeline control is critically important for animation synchronization: a desynchronization of even 16 ms (one frame at 60fps) is perceived by users as jank. At IT Sectr, we standardized timeline usage through ValueAnimator in Android and CABasicAnimation with CAMediaTiming in iOS — this ensures uniform time management across all projects.

Key Takeaways

  • Timeline — the concept of animation time management: duration, delay, repeat, mapping time to progress.
  • CAMediaTiming — iOS Core Animation protocol for timeline management: duration, beginTime, repeatCount, speed, timeOffset.
  • ValueAnimator — the central Android class for working with the animation timeline through duration, startDelay, repeatCount.
  • CACurrentMediaTime — iOS function for obtaining absolute time in seconds, used for synchronization.
  • TimeInterval — a data type in iOS (Double) representing a time interval for animation calculations.

What is Timeline?

Timeline is an animation time model that defines when an animation starts, how long it lasts, and how time progression is transformed into changes of the animated parameter. Unlike frame-by-frame animation where each frame is set manually, timeline animation is described by parameters: duration — total length, startDelay — delay before start, repeatCount — number of repetitions, and timingFunction — the speed curve.

The timeline operates in normalized space [0, 1] — local time or progress. A zero value corresponds to the start of the animation, one to completion. An easing function converts linear local time into actual animation progress. If repeatCount > 1, the timeline cycles (RESTART) or inverts (REVERSE). In iOS, CAMediaTiming adds speed (playback rate, >1 accelerates) and timeOffset (timeline shift). In Android, Animator uses setCurrentPlayTime() for direct timeline position control. According to Material Design, animations shorter than 100 ms are not perceived as animations, while those longer than 500 ms start to irritate. The optimal duration for interface animations is 200–350 ms.

Timeline in iOS: CAMediaTiming and CACurrentMediaTime

In iOS, animation timeline management is handled through the CAMediaTiming protocol, implemented by CAAnimation and CALayer. It provides properties: duration (in seconds), beginTime (start time relative to the parent timeline), repeatCount (number of repetitions), repeatDuration (total repeat duration), autoreverses (auto-reverse), fillMode (behavior before/after animation), speed (playback rate), and timeOffset (timeline shift).

CACurrentMediaTime() is a function that returns the absolute time in seconds since the last device reboot. It is used as a base timestamp for synchronizing multiple animations: set beginTime = CACurrentMediaTime() + offset to start a group of animations with precise delay. CAMediaTiming also supports timeline hierarchy — a parent layer can speed up/slow down all child animations through the speed property. In UIKit, UIViewPropertyAnimator (iOS 10+) abstracts the timeline through duration, delay properties and startAnimation/pauseAnimation/stopAnimation callbacks. In SwiftUI, the Animation structure provides duration as part of the animation specification, but direct timeline control is hidden — for custom timeline use TimelineView (iOS 15+) with a custom scheduler.

Timeline in Android: Animator and duration

In Android, timeline management is centralized in the Animator class and its subclasses (ValueAnimator, ObjectAnimator). The main timeline properties are: duration (in milliseconds), startDelay (delay before start), repeatCount (number of repetitions), repeatMode (RESTART or REVERSE). The setCurrentPlayTime(long) method allows navigating the timeline to any arbitrary position.

ValueAnimator adds an abstraction layer: it generates values from 0 to 1 (normalized time) based on duration and passes them to TimeInterpolator. AnimatorSet allows combining multiple Animators into a single timeline with sequential (playSequentially) or parallel (playTogether) execution. In Jetpack Compose, the timeline is managed through AnimationSpec: tween (durationMillis, delayMillis, easing), spring (dampingRatio, stiffness), and keyframes (points on the timeline with custom easing for each segment). Compose AnimatedContent uses a timeline for transitionSpec — the developer describes how content appears/disappears with time offsets. According to Android Performance, the animation timeline should be a multiple of 16 ms (vsync cycle) for 60fps — incorrect duration can cause frame drops due to mismatch with the display refresh rate.

Animation Composition in Time

The timeline becomes especially important when composing multiple animations. Three basic patterns: cascade — animations start sequentially with an offset (each next one starts after an offset from the previous), parallel — all animations start simultaneously with the same timeline, and stagger — animations start with overlap (the second starts before the first completes).

In iOS, cascade is implemented through each CAAnimation's beginTime = previous beginTime + previous duration. For stagger, CAAnimationGroup is used with different beginTime values for nested animations. In Android, AnimatorSet supports playSequentially and playTogether; stagger is created by setting startDelay for each Animator. In Compose, AnimatedVisibility with enter/exitTransition uses stagger in the staggerChildren variant for cascading appearance of list items. At WWDC and Google I/O 2024, both platforms introduced timeline visualization tools: Xcode Animations Inspector and Android Studio Animations Timeline — they show the actual timeline and dropped frames in real time.

Code Examples

iOS: CABasicAnimation with CAMediaTiming

An example of animation with a custom timeline: 0.3 sec delay, 0.6 sec duration, autoreverse, and infinite repeat. CAMediaTiming controls all timing parameters.

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 provides a 300 ms delay. autoreverses = true makes the animation run in reverse after each cycle. repeatCount = .infinity creates an infinite loop of the “breathing” effect. speed = 1.0 — normal speed; accelerate the animation 2x with a value of 2.0.

iOS: TimelineView for Custom Timeline

SwiftUI TimelineView (iOS 15+) provides access to the system timeline for custom animation. The View updates on each scheduler tick.

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 with .periodic scheduler generates ticks every 0.1 sec. In the closure, context.date is the current time, which is converted into a sine wave phase. The circle size pulses at 1 Hz frequency. TimelineView is the only way to create an animation with its own timeline in SwiftUI without the Animation API.

Android: ValueAnimator with Custom Timeline

ValueAnimator with full timeline control: delay, duration, repetition. The setCurrentPlayTime method allows jumping along the timeline.

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 — delay before start. repeatMode = REVERSE returns the animation to the initial value. animatedFraction gives progress from 0 to 1 accounting for repeatMode. addUpdateListener fires every frame (typically 16 ms). Use pause() / resume() for pausing.

Android: AnimatorSet for Timeline Composition

AnimatorSet allows creating complex timelines from multiple animations. The example demonstrates sequential execution with overlap (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 starts all animations in parallel, but each has its own startDelay — this creates a stagger effect: fadeIn starts first (0 ms), slideUp after 100 ms, scale after 200 ms. The resulting timeline: 0 — 100 — 200 — 600 ms. For sequential execution, use playSequentially.

Frequently Asked Questions

How is Animator different from ValueAnimator in Android?

Animator is an abstract base class for all animations. ValueAnimator is its subclass that animates numeric values without binding to an object. ObjectAnimator (a subclass of ValueAnimator) animates a specific object property (e.g., alpha or translationY). For timeline, use ValueAnimator as a universal timer with a callback via addUpdateListener.

How to synchronize animations on different devices?

Use system clocks (CACurrentMediaTime in iOS, System.nanoTime in Android) to calculate progress, not frame count. For network synchronization, use an NTP-based timer with offset correction. iOS supports AVAudioSession for audio-video timeline synchronization with millisecond precision. Avoid frame-based synchronization — frame rates vary from 30 to 120 fps.

What are startOffset and repeatCount in Animator?

startOffset is the delay before animation start in milliseconds. Used for cascade and stagger effects. repeatCount is the number of repetitions: 0 = no repeat, ValueAnimator.INFINITE = infinite loop. repeatMode determines direction: RESTART (reset to beginning) or REVERSE (reverse direction). In iOS, startOffset is called beginTime (in combination with CACurrentMediaTime), repeatCount is the same property of CABasicAnimation.

What is the optimal animation duration?

Material Design recommends 200–350 ms for interface animations. Animations shorter than 100 ms are not perceived as animations, while those longer than 500 ms are irritating. For entry/exit of elements: 200–300 ms. For transitions between screens: 300–400 ms. Use shorter durations for small elements (100–200 ms) and longer ones for large elements (400–500 ms).

Why does animation jank during playback?

Jank occurs due to: long-running operations on the main thread (blocking rendering), complex View/Layer hierarchy with overdraw, or incorrect timeline usage (duration not a multiple of vsync — 16ms for 60fps, 8ms for 120fps). Use Xcode Instruments Animations or Android Studio Profiler to detect dropped frames. In Compose, use Modifier.drawWithCache to cache complex drawings.

Summary

  • Timeline is an animation time model with duration, startDelay, repeatCount, repeatMode parameters that define the animation flow.
  • iOS CAMediaTiming protocol manages the timeline through duration, beginTime, speed, timeOffset, repeatCount, fillMode.
  • Android Animator and ValueAnimator provide duration, startDelay, repeatCount, repeatMode and setCurrentPlayTime for direct control.
  • AnimatorSet in Android and CAAnimationGroup in iOS allow combining animations into a single timeline.
  • TimelineView in SwiftUI (iOS 15+) provides access to the system scheduler for custom timelines without the Animation API.
  • CACurrentMediaTime() in iOS and System.nanoTime in Android are base timestamps for animation synchronization.
  • The optimal duration for interface animations is 200-350 ms according to Material Design and HIG recommendations.

We will develop a mobile application turnkey

IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.

Discuss the project

Read also