Timeline — основи, управљање временом анимације у апликацијама

Аутор: IT Sectr Објављено: 2026-03-02 Време читања: 8 мин
Timeline (временска линија) — фундаментални концепт анимације који одређује колико дуго траје анимација, којим редом се извршавају њене фазе и како се време пресликава на напредак. У развоју мобилних апликација, timeline се управља кроз трајање (duration), кашњење (delay), понављање (repeat) и временске ознаке. У iOS-у, анимациони timeline је имплементиран кроз CACurrentMediaTime и CAMediaTiming, у Android-у — кроз ValueAnimator и Animator са параметрима duration, startDelay и repeatCount. Према Apple документацији, прецизно управљање временском линијом је критично за синхронизацију анимација: десинхронизација чак и од 16 ms (један кадар при 60fps) се перципира од стране корисника као трзање. У IT Sectr-у смо стандардизовали коришћење timeline-а кроз ValueAnimator у Android-у и CABasicAnimation са CAMediaTiming у iOS-у — ово обезбеђује јединствено управљање временом у свим пројектима.

Главно

  • Timeline — концепт управљања временом анимације: duration, delay, repeat, пресликавање времена на напредак.
  • CAMediaTiming — протокол iOS Core Animation за управљање timeline-ом: duration, beginTime, repeatCount, speed, timeOffset.
  • ValueAnimator — централна класа Android-а за рад са временском линијом анимације кроз duration, startDelay, repeatCount.
  • CACurrentMediaTime — функција iOS-а за добијање апсолутног времена у секундама, користи се за синхронизацију.
  • TimeInterval — тип података у iOS-у (Double) који представља временски интервал за прорачуне анимације.

Шта је Timeline?

Timeline — модел времена анимације који одређује када анимација почиње, колико дуго траје и како се проток времена претвара у промену анимираног параметра. За разлику од анимације кадар по кадар (frame-by-frame), где се сваки кадар поставља ручно, timeline анимација се описује параметрима: duration — укупно трајање, startDelay — кашњење пре почетка, repeatCount — број понављања и timingFunction — крива брзине.

Временска линија ради у нормализованом простору [0, 1] — local time или progress. Нулта вредност одговара почетку анимације, јединица — завршетку. Easing функција претвара линеарни local time у стварни напредак анимације. Ако је repeatCount > 1, timeline се циклично ресетује (RESTART) или инвертује (REVERSE). У iOS-у, CAMediaTiming додаје параметре speed (брзина репродукције, >1 убрзава) и timeOffset (померај временске линије). У Android-у, Animator користи setCurrentPlayTime() за директно управљање позицијом на временској линији. Према Material Design-у, анимације краће од 100 ms се не перципирају као анимација, а дуже од 500 ms — почињу да иритирају. Оптимално трајање за интерфејс анимације је 200–350 ms.

Timeline у iOS-у: CAMediaTiming и CACurrentMediaTime

У iOS-у, управљање временском линијом анимације се врши кроз протокол CAMediaTiming, који имплементирају CAAnimation и CALayer. Он пружа својства: duration (трајање у секундама), beginTime (време почетка у односу на родитељски timeline), repeatCount (број понављања), repeatDuration (укупно трајање понављања), autoreverses (аутоматски обрнути правац), fillMode (понашање пре/после анимације), speed (брзина репродукције) и timeOffset (померај на линији).

CACurrentMediaTime() — функција која враћа апсолутно време у секундама од последњег рестартовања уређаја. Користи се као основни временски ознака за синхронизацију више анимација: подесите beginTime = CACurrentMediaTime() + offset за покретање групе анимација са прецизним кашњењем. CAMediaTiming такође подржава хијерархију timeline-а — родитељски слој може убрзати/успорити све подређене анимације кроз својство speed. У UIKit-у, UIViewPropertyAnimator (iOS 10+) апстрахује временску линију кроз својства duration, delay и колбеке startAnimation/pauseAnimation/stopAnimation. У SwiftUI-ју, структура Animation пружа duration као део спецификације анимације, али директно управљање временском линијом је скривено — за прилагођени timeline користите TimelineView (iOS 15+) са сопственим scheduler-ом.

Timeline у Android-у: Animator и duration

У Android-у, управљање временском линијом је централизовано у класи Animator и њеним наследницима (ValueAnimator, ObjectAnimator). Основна својства timeline-а: duration (трајање у милисекундама), startDelay (кашњење пре почетка), repeatCount (број понављања), repeatMode (RESTART или REVERSE). Метод setCurrentPlayTime(long) омогућава кретање по временској линији на произвољну позицију.

ValueAnimator додаје ниво апстракције: генерише вредности од 0 до 1 (normalized time) на основу duration и прослеђује их TimeInterpolator-у. AnimatorSet омогућава комбиновање више Animator-а у једну временску линију са секвенцијалним (playSequentially) или паралелним (playTogether) извршавањем. У Jetpack Compose-у, временска линија се управља кроз AnimationSpec: tween (durationMillis, delayMillis, easing), spring (dampingRatio, stiffness) и keyframes (тачке на временској линији са прилагођеним easing-ом за сваки сегмент). Compose AnimatedContent користи timeline за transitionSpec — програмер описује како садржај постаје/нестаје са временским померајима. Према Android Performance-у, временска линија анимације треба да буде умножак од 16 ms (vsync циклус) за 60fps — неправилно трајање може изазвати прескакање кадрова због неслагања са стопом освежавања екрана.

Композиција анимација у времену

Временска линија постаје посебно важна при композицији више анимација. Три основна обрасца: каскада — анимације се покрећу секвенцијално са померајем (свака следећа почиње након offset-а од претходне), паралела — све анимације се покрећу истовремено са истим timeline-ом и stagger — анимације се покрећу са преклапањем (друга почиње пре завршетка прве).

У iOS-у, каскада се имплементира кроз beginTime сваке CAAnimation = претходна beginTime + претходна duration. За stagger се користи CAAnimationGroup са различитим beginTime у угнежђеним анимацијама. У Android-у, AnimatorSet подржава playSequentially и playTogether; stagger се ствара подешавањем startDelay за сваки Animator. У Compose-у, AnimatedVisibility са enter/exitTransition користи stagger у варијанти staggerChildren за каскадно појављивање елемената листе. На WWDC и Google I/O 2024, обе платформе су представиле алате за визуелизацију timeline-а: Xcode Animations Inspector и Android Studio Animations Timeline — они приказују стварну временску линију и прескочене кадрове у реалном времену.

Примери кода

iOS: CABasicAnimation са CAMediaTiming

Пример анимације са прилагођеним timeline-ом: кашњење 0.3 сек, трајање 0.6 сек, autoreverse и бесконачно понављање. CAMediaTiming управља свим временским параметрима.

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 даје кашњење од 300 ms. autoreverses = true узрокује да анимација иде у супротном смеру након сваког циклуса. repeatCount = .infinity ствара бесконачну петљу ефекта "дисања". speed = 1.0 — нормална брзина; убрзајте анимацију 2 пута вредношћу 2.0.

iOS: TimelineView за прилагођену временску линију

SwiftUI TimelineView (iOS 15+) пружа приступ системском timeline-у за прилагођену анимацију. Поглед се ажурира при сваком откуцају 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 са .periodic scheduler-ом генерише откуцаје сваких 0.1 сек. У затварању context.date — тренутно време које се претвара у фазу синусоиде. Величина круга пулсира са фреквенцијом од 1 Hz. TimelineView је једини начин да се креира анимација са сопственом временском линијом у SwiftUI-ју без Animation API.

Android: ValueAnimator са прилагођеним timeline-ом

ValueAnimator са комплетним управљањем временском линијом: кашњење, трајање, понављање. Метод setCurrentPlayTime омогућава скакање по временској линији.

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 — кашњење пре почетка. repeatMode = REVERSE враћа анимацију на почетну вредност. animatedFraction даје напредак од 0 до 1 узимајући у обзир repeatMode. addUpdateListener се покреће сваки кадар (обично 16 ms). За паузирање користите pause() / resume().

Android: AnimatorSet за композицију timeline-а

AnimatorSet омогућава креирање сложених временских линија од више анимација. У примеру — секвенцијално извршавање са преклапањем (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 покреће све анимације паралелно, али свака има свој startDelay — ово ствара stagger ефекат: fadeIn почиње први (0 ms), slideUp након 100 ms, scale након 200 ms. Резултујућа временска линија: 0 — 100 — 200 — 600 ms. За секвенцијално извршавање користите playSequentially.

Често постављана питања

По чему се Animator разликује од ValueAnimator у Android-у?

Animator — апстрактна базна класа за све анимације. ValueAnimator — њена подкласа која анимира нумеричке вредности без везивања за објекат. ObjectAnimator (наследник ValueAnimator) анимира одређено својство објекта (нпр. alpha или translationY). За timeline користите ValueAnimator као универзални тајмер са колбеком кроз addUpdateListener.

Како синхронизовати анимације на различитим уређајима?

Користите системске сатове (CACurrentMediaTime у iOS-у, System.nanoTime у Android-у) за израчунавање напретка, а не број кадрова. За мрежну синхронизацију примените тајмер заснован на NTP-у са корекцијом offset. iOS подржава AVAudioSession за синхронизацију аудио-видео timeline-а са прецизношћу до милисекунди. Избегавајте синхронизацију по кадровима — брзина кадрова варира од 30 до 120 fps.

Шта су startOffset и repeatCount у Animator-у?

startOffset — кашњење пре почетка анимације у милисекундама. Користи се за каскаду и stagger ефекте. repeatCount — број понављања: 0 = без понављања, ValueAnimator.INFINITE = бесконачна петља. repeatMode одређује смер: RESTART (ресетовање на почетак) или REVERSE (обрнути смер). У iOS-у, startOffset се назива beginTime (у комбинацији са CACurrentMediaTime), repeatCount — истоимено својство CABasicAnimation.

Које је оптимално трајање анимације?

Material Design препоручује 200–350 ms за интерфејс анимације. Анимације краће од 100 ms се не перципирају као анимација, дуже од 500 ms — иритирају. За улаз/излаз елемената: 200–300 ms. За транзиције између екрана: 300–400 ms. Користите краћа трајања за мале елементе (100–200 ms) и дужа за велике (400–500 ms).

Зашто анимација трза током репродукције?

Трзање (jank) настаје због: дуготрајних операција у главној нити (блокирају рендеровање), сложене хијерархије View/Layer са overdraw, или неправилног коришћења timeline-а (трајање није умножак vsync-а — 16ms за 60fps, 8ms за 120fps). Користите Xcode Instruments Animations или Android Studio Profiler за откривање прескочених кадрова. У Compose-у примените Modifier.drawWithCache за кеширање сложених цртежа.

Резиме

  • Timeline — модел времена анимације са параметрима duration, startDelay, repeatCount, repeatMode, који одређује ток анимације.
  • iOS CAMediaTiming протокол управља временском линијом кроз duration, beginTime, speed, timeOffset, repeatCount, fillMode.
  • Android Animator и ValueAnimator пружају duration, startDelay, repeatCount, repeatMode и setCurrentPlayTime за директно управљање.
  • AnimatorSet у Android-у и CAAnimationGroup у iOS-у омогућавају комбиновање анимација у једну временску линију.
  • TimelineView у SwiftUI-ју (iOS 15+) пружа приступ системском scheduler-у за прилагођене временске линије без Animation API.
  • CACurrentMediaTime() у iOS-у и System.nanoTime у Android-у — основне временске ознаке за синхронизацију анимација.
  • Оптимално трајање интерфејс анимација — 200-350 ms према препорукама Material Design и HIG.

Развићемо мобилну апликацију под кључ

IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.

Разговарајте о пројекту

Прочитајте такође