Poin Utama
Timeline — adalah model waktu animasi yang menentukan kapan animasi dimulai, berapa lama berlangsung, dan bagaimana perjalanan waktu diubah menjadi perubahan parameter yang dianimasikan. Tidak seperti animasi bingkai demi bingkai (frame-by-frame), di mana setiap bingkai diatur secara manual, animasi timeline dijelaskan dengan parameter: duration — durasi total, startDelay — penundaan sebelum mulai, repeatCount — jumlah pengulangan, dan timingFunction — kurva kecepatan.
Garis waktu bekerja dalam ruang yang dinormalisasi [0, 1] — local time atau progress. Nilai nol sesuai dengan awal animasi, satu — dengan akhir. Fungsi easing mengubah local time linier menjadi kemajuan animasi yang sebenarnya. Jika repeatCount > 1, timeline secara siklis di-reset (RESTART) atau dibalik (REVERSE). Di iOS, CAMediaTiming menambahkan parameter speed (kecepatan pemutaran, >1 mempercepat) dan timeOffset (pergeseran garis waktu). Di Android, Animator menggunakan setCurrentPlayTime() untuk pengelolaan posisi langsung pada garis waktu. Menurut Material Design, animasi yang lebih pendek dari 100 ms tidak dirasakan sebagai animasi, dan yang lebih panjang dari 500 ms — mulai mengganggu. Durasi optimal untuk animasi antarmuka adalah 200–350 ms.
Di iOS, pengelolaan garis waktu animasi dilakukan melalui protokol CAMediaTiming, yang diimplementasikan oleh CAAnimation dan CALayer. Ini menyediakan properti: duration (durasi dalam detik), beginTime (waktu mulai relatif terhadap timeline induk), repeatCount (jumlah pengulangan), repeatDuration (total durasi pengulangan), autoreverses (gerakan mundur otomatis), fillMode (perilaku sebelum/setelah animasi), speed (kecepatan pemutaran), dan timeOffset (pergeseran pada garis).
CACurrentMediaTime() — fungsi yang mengembalikan waktu absolut dalam detik sejak restart terakhir perangkat. Digunakan sebagai stempel waktu dasar untuk sinkronisasi beberapa animasi: atur beginTime = CACurrentMediaTime() + offset untuk memulai grup animasi dengan penundaan yang tepat. CAMediaTiming juga mendukung hierarki timeline — lapisan induk dapat mempercepat/memperlambat semua animasi anak melalui properti speed. Di UIKit, UIViewPropertyAnimator (iOS 10+) mengabstraksi garis waktu melalui properti duration, delay, dan callback startAnimation/pauseAnimation/stopAnimation. Di SwiftUI, struktur Animation menyediakan duration sebagai bagian dari spesifikasi animasi, tetapi pengelolaan langsung garis waktu tersembunyi — untuk timeline kustom gunakan TimelineView (iOS 15+) dengan scheduler sendiri.
Di Android, pengelolaan garis waktu terpusat di kelas Animator dan turunannya (ValueAnimator, ObjectAnimator). Properti utama timeline: duration (durasi dalam milidetik), startDelay (penundaan sebelum mulai), repeatCount (jumlah pengulangan), repeatMode (RESTART atau REVERSE). Metode setCurrentPlayTime(long) memungkinkan pergerakan ke posisi mana pun pada garis waktu.
ValueAnimator menambahkan tingkat abstraksi: menghasilkan nilai dari 0 hingga 1 (normalized time) berdasarkan duration dan meneruskannya ke TimeInterpolator. AnimatorSet memungkinkan penggabungan beberapa Animator menjadi satu garis waktu dengan eksekusi berurutan (playSequentially) atau paralel (playTogether). Di Jetpack Compose, garis waktu dikelola melalui AnimationSpec: tween (durationMillis, delayMillis, easing), spring (dampingRatio, stiffness), dan keyframes (titik pada garis waktu dengan easing kustom untuk setiap segmen). Compose AnimatedContent menggunakan timeline untuk transitionSpec — pengembang menjelaskan bagaimana konten muncul/hilang dengan pergeseran waktu. Menurut Android Performance, garis waktu animasi harus kelipatan 16 ms (siklus vsync) untuk 60fps — durasi yang salah dapat menyebabkan frame loss karena ketidakcocokan dengan refresh rate layar.
Garis waktu menjadi sangat penting dalam komposisi beberapa animasi. Tiga pola dasar: kaskade — animasi dimulai secara berurutan dengan pergeseran (setiap berikutnya dimulai setelah offset dari sebelumnya), paralel — semua animasi dimulai secara bersamaan dengan timeline yang sama, dan stagger — animasi dimulai dengan tumpang tindih (yang kedua dimulai sebelum yang pertama selesai).
Di iOS, kaskade diimplementasikan melalui beginTime setiap CAAnimation = beginTime sebelumnya + duration sebelumnya. Untuk stagger, digunakan CAAnimationGroup dengan beginTime berbeda dalam animasi bersarang. Di Android, AnimatorSet mendukung playSequentially dan playTogether; stagger dibuat dengan mengatur startDelay untuk setiap Animator. Di Compose, AnimatedVisibility dengan enter/exitTransition menggunakan stagger dalam varian staggerChildren untuk kemunculan berjenjang elemen daftar. Di WWDC dan Google I/O 2024, kedua platform memperkenalkan alat visualisasi timeline: Xcode Animations Inspector dan Android Studio Animations Timeline — mereka menunjukkan garis waktu aktual dan frame yang terlewat secara real-time.
Contoh animasi dengan timeline kustom: penundaan 0,3 detik, durasi 0,6 detik, autoreverse, dan pengulangan tak terbatas. CAMediaTiming mengelola semua parameter waktu.
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 memberikan penundaan 300 ms. autoreverses = true menyebabkan animasi bergerak ke arah berlawanan setelah setiap siklus. repeatCount = .infinity menciptakan loop tak terbatas dari efek “bernafas”. speed = 1,0 — kecepatan normal; percepat animasi 2 kali dengan nilai 2,0.
SwiftUI TimelineView (iOS 15+) menyediakan akses ke timeline sistem untuk animasi kustom. Tampilan diperbarui pada setiap tick scheduler.
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 dengan scheduler .periodic menghasilkan tick setiap 0,1 detik. Dalam closure, context.date — waktu saat ini yang diubah menjadi fase sinusoida. Ukuran lingkaran berdenyut dengan frekuensi 1 Hz. TimelineView adalah satu-satunya cara untuk membuat animasi dengan garis waktu sendiri di SwiftUI tanpa Animation API.
ValueAnimator dengan pengelolaan garis waktu penuh: penundaan, durasi, pengulangan. Metode setCurrentPlayTime memungkinkan melompat pada garis waktu.
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 — penundaan sebelum mulai. repeatMode = REVERSE mengembalikan animasi ke nilai awal. animatedFraction memberikan kemajuan dari 0 hingga 1 dengan mempertimbangkan repeatMode. addUpdateListener dipanggil setiap frame (biasanya 16 ms). Untuk menjeda, gunakan pause() / resume().
AnimatorSet memungkinkan pembuatan garis waktu kompleks dari beberapa animasi. Dalam contoh — eksekusi berurutan dengan tumpang tindih (stagger).
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 memulai semua animasi secara paralel, tetapi setiap animasi memiliki startDelay sendiri — ini menciptakan efek stagger: fadeIn mulai pertama (0 ms), slideUp setelah 100 ms, scale setelah 200 ms. Garis waktu yang dihasilkan: 0 — 100 — 200 — 600 ms. Untuk eksekusi berurutan, gunakan playSequentially.
Pertanyaan Umum
Animator — kelas dasar abstrak untuk semua animasi. ValueAnimator — subkelasnya yang menganimasi nilai numerik tanpa terikat ke objek. ObjectAnimator (pewaris ValueAnimator) menganimasi properti spesifik objek (misalnya, alpha atau translationY). Untuk timeline, gunakan ValueAnimator sebagai timer universal dengan callback melalui addUpdateListener.
Gunakan jam sistem (CACurrentMediaTime di iOS, System.nanoTime di Android) untuk menghitung kemajuan, bukan jumlah frame. Untuk sinkronisasi jaringan, gunakan timer berbasis NTP dengan koreksi offset. iOS mendukung AVAudioSession untuk sinkronisasi timeline audio-video dengan akurasi milidetik. Hindari sinkronisasi berdasarkan frame — frame rate bervariasi dari 30 hingga 120 fps.
startOffset — penundaan sebelum memulai animasi dalam milidetik. Digunakan untuk efek kaskade dan stagger. repeatCount — jumlah pengulangan: 0 = tidak diulang, ValueAnimator.INFINITE = loop tak terbatas. repeatMode menentukan arah: RESTART (reset ke awal) atau REVERSE (gerakan mundur). Di iOS, startOffset disebut beginTime (dalam kombinasi dengan CACurrentMediaTime), repeatCount — properti dengan nama yang sama di CABasicAnimation.
Material Design merekomendasikan 200–350 ms untuk animasi antarmuka. Animasi lebih pendek dari 100 ms tidak dirasakan sebagai animasi, lebih panjang dari 500 ms — mengganggu. Untuk masuk/keluar elemen: 200–300 ms. Untuk transisi antar layar: 300–400 ms. Gunakan durasi lebih pendek untuk elemen kecil (100–200 ms) dan lebih panjang untuk elemen besar (400–500 ms).
Tersendat (jank) terjadi karena: operasi lama di thread utama (memblokir rendering), hierarki View/Layer kompleks dengan overdraw, atau penggunaan timeline yang salah (durasi bukan kelipatan vsync — 16ms untuk 60fps, 8ms untuk 120fps). Gunakan Xcode Instruments Animations atau Android Studio Profiler untuk mendeteksi frame yang terlewat. Di Compose, gunakan Modifier.drawWithCache untuk caching gambar kompleks.
Ringkasan
Kami akan mengembangkan aplikasi seluler turnkey
IT Sectr membuat aplikasi iOS dan Android untuk startup dan bisnis sejak 2017. Kami akan memberi saran dan mengusulkan solusi terbaik.
Baca juga