Timeline — fondamenti, gestione del tempo di animazione nelle applicazioni

Autore: IT Sectr Pubblicato: 2026-03-02 Tempo di lettura: 8 min
Timeline (linea temporale) è un concetto fondamentale dell'animazione che determina per quanto tempo dura un'animazione, in quale ordine vengono eseguite le sue fasi e come il tempo viene mappato sul progresso. Nello sviluppo di app mobili, la timeline viene gestita attraverso durata (duration), ritardo (delay), ripetizioni (repeat) e timestamp. In iOS, la timeline dell'animazione è implementata tramite CACurrentMediaTime e CAMediaTiming, mentre in Android utilizza ValueAnimator e Animator con i parametri duration, startDelay e repeatCount. Secondo Apple Documentation, il controllo preciso della timeline è criticamente importante per la sincronizzazione delle animazioni: una desincronizzazione di soli 16 ms (un fotogramma a 60fps) viene percepita dall'utente come scatto. In IT Sectr, abbiamo standardizzato l'uso della timeline tramite ValueAnimator in Android e CABasicAnimation con CAMediaTiming in iOS — ciò garantisce una gestione uniforme del tempo in tutti i progetti.

Punti Chiave

  • Timeline — il concetto di gestione del tempo di animazione: duration, delay, repeat, mappatura del tempo sul progresso.
  • CAMediaTiming — protocollo iOS Core Animation per la gestione della timeline: duration, beginTime, repeatCount, speed, timeOffset.
  • ValueAnimator — la classe centrale di Android per lavorare con la timeline di animazione tramite duration, startDelay, repeatCount.
  • CACurrentMediaTime — funzione iOS per ottenere il tempo assoluto in secondi, utilizzata per la sincronizzazione.
  • TimeInterval — un tipo di dato in iOS (Double) che rappresenta un intervallo di tempo per i calcoli di animazione.

Cos'è Timeline?

Timeline è un modello temporale di animazione che definisce quando un'animazione inizia, quanto dura e come il progredire del tempo viene trasformato in cambiamenti del parametro animato. A differenza dell'animazione fotogramma per fotogramma (frame-by-frame), dove ogni fotogramma è impostato manualmente, l'animazione tramite timeline è descritta da parametri: duration — durata totale, startDelay — ritardo prima dell'inizio, repeatCount — numero di ripetizioni, e timingFunction — la curva di velocità.

La timeline opera in uno spazio normalizzato [0, 1] — tempo locale o progresso. Il valore zero corrisponde all'inizio dell'animazione, uno al completamento. Una funzione di easing (smussamento) converte il tempo locale lineare in progresso effettivo dell'animazione. Se repeatCount > 1, la timeline cicla (RESTART) o si inverte (REVERSE). In iOS, CAMediaTiming aggiunge speed (velocità di riproduzione, >1 accelera) e timeOffset (spostamento della timeline). In Android, Animator utilizza setCurrentPlayTime() per il controllo diretto della posizione sulla timeline. Secondo Material Design, le animazioni più corte di 100 ms non vengono percepite come animazioni, mentre quelle più lunghe di 500 ms iniziano a irritare. La durata ottimale per le animazioni di interfaccia è di 200–350 ms.

Timeline in iOS: CAMediaTiming e CACurrentMediaTime

In iOS, la gestione della timeline di animazione è gestita attraverso il protocollo CAMediaTiming, implementato da CAAnimation e CALayer. Fornisce le proprietà: duration (in secondi), beginTime (tempo di inizio relativo alla timeline genitore), repeatCount (numero di ripetizioni), repeatDuration (durata totale delle ripetizioni), autoreverses (inversione automatica), fillMode (comportamento prima/dopo l'animazione), speed (velocità di riproduzione) e timeOffset (spostamento della timeline).

CACurrentMediaTime() è una funzione che restituisce il tempo assoluto in secondi dall'ultimo riavvio del dispositivo. Viene utilizzata come timestamp di base per sincronizzare più animazioni: impostare beginTime = CACurrentMediaTime() + offset per avviare un gruppo di animazioni con un ritardo preciso. CAMediaTiming supporta anche la gerarchia della timeline — un livello genitore può accelerare/rallentare tutte le animazioni figlie attraverso la proprietà speed. In UIKit, UIViewPropertyAnimator (iOS 10+) astrae la timeline attraverso le proprietà duration, delay e i callback startAnimation/pauseAnimation/stopAnimation. In SwiftUI, la struttura Animation fornisce duration come parte della specifica dell'animazione, ma il controllo diretto della timeline è nascosto — per una timeline personalizzata, utilizzare TimelineView (iOS 15+) con uno scheduler personalizzato.

Timeline in Android: Animator e duration

In Android, la gestione della timeline è centralizzata nella classe Animator e nelle sue sottoclassi (ValueAnimator, ObjectAnimator). Le principali proprietà della timeline sono: duration (in millisecondi), startDelay (ritardo prima dell'inizio), repeatCount (numero di ripetizioni), repeatMode (RESTART o REVERSE). Il metodo setCurrentPlayTime(long) consente di navigare sulla timeline in qualsiasi posizione arbitraria.

ValueAnimator aggiunge un livello di astrazione: genera valori da 0 a 1 (tempo normalizzato) basati sulla duration e li passa a TimeInterpolator. AnimatorSet consente di combinare più Animator in un'unica timeline con esecuzione sequenziale (playSequentially) o parallela (playTogether). In Jetpack Compose, la timeline è gestita tramite AnimationSpec: tween (durationMillis, delayMillis, easing), spring (dampingRatio, stiffness) e keyframes (punti sulla timeline con easing personalizzato per ogni segmento). Compose AnimatedContent utilizza una timeline per transitionSpec — lo sviluppatore descrive come il contenuto appare/scompare con offset temporali. Secondo Android Performance, la timeline di animazione dovrebbe essere un multiplo di 16 ms (ciclo vsync) per 60fps — una durata errata può causare perdita di fotogrammi a causa della mancata corrispondenza con la frequenza di aggiornamento del display.

Composizione delle animazioni nel tempo

La timeline diventa particolarmente importante quando si compongono più animazioni. Tre modelli di base: cascata — le animazioni partono in sequenza con un offset (ogni successiva inizia dopo un offset dalla precedente), parallelo — tutte le animazioni iniziano simultaneamente con la stessa timeline, e stagger — le animazioni iniziano con sovrapposizione (la seconda inizia prima che la prima sia completata).

In iOS, la cascata è implementata tramite beginTime di ogni CAAnimation = beginTime precedente + duration precedente. Per lo stagger, CAAnimationGroup viene utilizzato con diversi valori di beginTime nelle animazioni annidate. In Android, AnimatorSet supporta playSequentially e playTogether; lo stagger viene creato impostando startDelay per ogni Animator. In Compose, AnimatedVisibility con enter/exitTransition utilizza lo stagger nella variante staggerChildren per l'apparizione a cascata degli elementi dell'elenco. Alla WWDC e Google I/O 2024, entrambe le piattaforme hanno presentato strumenti di visualizzazione della timeline: Xcode Animations Inspector e Android Studio Animations Timeline — mostrano la timeline effettiva e i fotogrammi persi in tempo reale.

Esempi di codice

iOS: CABasicAnimation con CAMediaTiming

Un esempio di animazione con timeline personalizzata: ritardo di 0,3 s, durata di 0,6 s, inversione automatica e ripetizione infinita. CAMediaTiming controlla tutti i parametri temporali.

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 fornisce un ritardo di 300 ms. autoreverses = true fa eseguire l'animazione in direzione inversa dopo ogni ciclo. repeatCount = .infinity crea un ciclo infinito dell'effetto “respirazione”. speed = 1,0 — velocità normale; accelerare l'animazione 2x con un valore di 2,0.

iOS: TimelineView per Timeline Personalizzata

SwiftUI TimelineView (iOS 15+) fornisce accesso alla timeline di sistema per animazioni personalizzate. La View si aggiorna a ogni tick dello 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 tick ogni 0,1 s. Nella chiusura, context.date è l'ora corrente, che viene convertita in una fase d'onda sinusoidale. La dimensione del cerchio pulsa a una frequenza di 1 Hz. TimelineView è l'unico modo per creare un'animazione con la propria timeline in SwiftUI senza l'API Animation.

Android: ValueAnimator con Timeline Personalizzata

ValueAnimator con controllo completo della timeline: ritardo, durata, ripetizione. Il metodo setCurrentPlayTime consente di saltare lungo la 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 — ritardo prima dell'inizio. repeatMode = REVERSE riporta l'animazione al valore iniziale. animatedFraction fornisce il progresso da 0 a 1 tenendo conto di repeatMode. addUpdateListener si attiva ogni fotogramma (in genere 16 ms). Utilizzare pause() / resume() per mettere in pausa.

Android: AnimatorSet per la Composizione della Timeline

AnimatorSet consente di creare timeline complesse da più animazioni. L'esempio dimostra l'esecuzione sequenziale con sovrapposizione (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 avvia tutte le animazioni in parallelo, ma ognuna ha il proprio startDelay — questo crea un effetto stagger: fadeIn parte per primo (0 ms), slideUp dopo 100 ms, scale dopo 200 ms. La timeline risultante: 0 — 100 — 200 — 600 ms. Per l'esecuzione sequenziale, utilizzare playSequentially.

Domande frequenti

In che modo Animator differisce da ValueAnimator in Android?

Animator è una classe base astratta per tutte le animazioni. ValueAnimator è la sua sottoclasse che anima valori numerici senza legarsi a un oggetto. ObjectAnimator (una sottoclasse di ValueAnimator) anima una proprietà specifica di un oggetto (ad esempio alpha o translationY). Per la timeline, utilizzare ValueAnimator come timer universale con un callback tramite addUpdateListener.

Come sincronizzare le animazioni su dispositivi diversi?

Utilizzare orologi di sistema (CACurrentMediaTime in iOS, System.nanoTime in Android) per calcolare il progresso, non il numero di fotogrammi. Per la sincronizzazione di rete, utilizzare un timer basato su NTP con correzione dell'offset. iOS supporta AVAudioSession per la sincronizzazione della timeline audio-video con precisione millisecondo. Evitare la sincronizzazione basata sui fotogrammi — le frequenze dei fotogrammi variano da 30 a 120 fps.

Cosa sono startOffset e repeatCount in Animator?

startOffset è il ritardo prima dell'inizio dell'animazione in millisecondi. Utilizzato per effetti a cascata e stagger. repeatCount è il numero di ripetizioni: 0 = nessuna ripetizione, ValueAnimator.INFINITE = ciclo infinito. repeatMode determina la direzione: RESTART (reimposta all'inizio) o REVERSE (direzione inversa). In iOS, startOffset si chiama beginTime (in combinazione con CACurrentMediaTime), repeatCount è la stessa proprietà di CABasicAnimation.

Qual è la durata ottimale dell'animazione?

Material Design consiglia 200–350 ms per le animazioni di interfaccia. Le animazioni più corte di 100 ms non vengono percepite come animazioni, mentre quelle più lunghe di 500 ms sono irritanti. Per ingresso/uscita degli elementi: 200–300 ms. Per transizioni tra schermate: 300–400 ms. Utilizzare durate più brevi per elementi piccoli (100–200 ms) e più lunghe per elementi grandi (400–500 ms).

Perché l'animazione scatta durante la riproduzione?

Gli scatti (jank) si verificano a causa di: operazioni di lunga durata sul thread principale (bloccano il rendering), gerarchia complessa di View/Layer con overdraw, o uso errato della timeline (durata non multipla di vsync — 16ms per 60fps, 8ms per 120fps). Utilizzare Xcode Instruments Animations o Android Studio Profiler per rilevare i fotogrammi persi. In Compose, utilizzare Modifier.drawWithCache per memorizzare nella cache disegni complessi.

Riepilogo

  • Timeline è un modello temporale di animazione con parametri duration, startDelay, repeatCount, repeatMode che definiscono il flusso dell'animazione.
  • Il protocollo iOS CAMediaTiming gestisce la timeline tramite duration, beginTime, speed, timeOffset, repeatCount, fillMode.
  • Android Animator e ValueAnimator forniscono duration, startDelay, repeatCount, repeatMode e setCurrentPlayTime per il controllo diretto.
  • AnimatorSet in Android e CAAnimationGroup in iOS consentono di combinare animazioni in un'unica timeline.
  • TimelineView in SwiftUI (iOS 15+) fornisce accesso allo scheduler di sistema per timeline personalizzate senza l'API Animation.
  • CACurrentMediaTime() in iOS e System.nanoTime in Android sono timestamp di base per la sincronizzazione delle animazioni.
  • La durata ottimale per le animazioni di interfaccia è di 200-350 ms secondo le raccomandazioni di Material Design e HIG.

Svilupperemo un'applicazione mobile chiavi in mano

IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.

Discuti il progetto

Leggi anche