Timeline — พื้นฐาน, การจัดการเวลาแอนิเมชันในแอปพลิเคชัน

ผู้แต่ง: IT Sectr เผยแพร่เมื่อ: 2026-03-02 เวลาอ่าน: 8 นาที
Timeline (เส้นเวลา) เป็นแนวคิดพื้นฐานของแอนิเมชันที่กำหนดว่าแอนิเมชันจะอยู่นานเท่าใด ลำดับการทำงานของขั้นตอนต่างๆ และวิธีการแมปเวลาไปยังความคืบหน้า ในการพัฒนาแอปมือถือ เส้นเวลาจะถูกจัดการผ่าน duration, delay, repeat และการประทับเวลา ใน iOS เส้นเวลาแอนิเมชันถูกนำไปใช้ผ่าน CACurrentMediaTime และ CAMediaTiming ในขณะที่ Android ใช้ ValueAnimator และ Animator พร้อมพารามิเตอร์ duration, startDelay และ repeatCount ตาม Apple Documentation การควบคุมเส้นเวลาที่แม่นยำมีความสำคัญอย่างยิ่งสำหรับ การซิงโครไนซ์แอนิเมชัน: การขาดการซิงค์แม้เพียง 16 ms (หนึ่งเฟรมที่ 60fps) ก็ถูกรับรู้โดยผู้ใช้ว่าเป็นการกระตุก ที่ IT Sectr เรามาตรฐานการใช้เส้นเวลาผ่าน ValueAnimator ใน Android และ CABasicAnimation กับ CAMediaTiming ใน iOS — ซึ่งช่วยให้การจัดการเวลาเป็นไปอย่างสม่ำเสมอในทุกโครงการ

ประเด็นสำคัญ

  • Timeline — แนวคิดการจัดการเวลาแอนิเมชัน: duration, delay, repeat, การแมปเวลาไปยังความคืบหน้า
  • CAMediaTiming — โพรโทคอล iOS Core Animation สำหรับการจัดการเส้นเวลา: duration, beginTime, repeatCount, speed, timeOffset
  • ValueAnimator — คลาสหลักของ Android สำหรับทำงานกับเส้นเวลาแอนิเมชันผ่าน duration, startDelay, repeatCount
  • CACurrentMediaTime — ฟังก์ชัน iOS สำหรับรับเวลาสัมบูรณ์เป็นวินาที ใช้สำหรับการซิงโครไนซ์
  • TimeInterval — ชนิดข้อมูลใน iOS (Double) ที่แสดงช่วงเวลาสำหรับการคำนวณแอนิเมชัน

Timeline คืออะไร?

Timeline คือแบบจำลองเวลาแอนิเมชันที่กำหนดว่าแอนิเมชันเริ่มต้นเมื่อใด อยู่นานเท่าใด และความก้าวหน้าของเวลาถูกแปลงเป็นการเปลี่ยนแปลงของพารามิเตอร์ที่ถูกทำให้เคลื่อนไหวอย่างไร แตกต่างจากแอนิเมชันแบบเฟรมต่อเฟรม (frame-by-frame) ซึ่งแต่ละเฟรมถูกตั้งค่าด้วยตนเอง แอนิเมชันแบบเส้นเวลาจะถูกอธิบายด้วยพารามิเตอร์: duration — ระยะเวลาทั้งหมด, startDelay — หน่วงเวลาก่อนเริ่ม, repeatCount — จำนวนการทำซ้ำ และ timingFunction — เส้นโค้งความเร็ว

เส้นเวลาทำงานในพื้นที่ปกติ [0, 1] — เวลาท้องถิ่นหรือความคืบหน้า ค่า 0 สอดคล้องกับจุดเริ่มต้นของแอนิเมชัน ค่า 1 สอดคล้องกับการเสร็จสิ้น ฟังก์ชัน easing (การทำให้เรียบ) แปลงเวลาท้องถิ่นเชิงเส้นเป็นความคืบหน้าแอนิเมชันจริง ถ้า repeatCount > 1 เส้นเวลาจะวนซ้ำ (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 (เวลาเริ่มต้นสัมพันธ์กับเส้นเวลาแม่), repeatCount (จำนวนการทำซ้ำ), repeatDuration (ระยะเวลาการทำซ้ำทั้งหมด), autoreverses (การกลับทิศอัตโนมัติ), fillMode (พฤติกรรมก่อน/หลังแอนิเมชัน), speed (อัตราการเล่น) และ timeOffset (การเลื่อนเส้นเวลา)

CACurrentMediaTime() เป็นฟังก์ชันที่คืนเวลาสัมบูรณ์เป็นวินาทีตั้งแต่การรีบูตอุปกรณ์ครั้งล่าสุด ใช้เป็นประทับเวลาพื้นฐานสำหรับการซิงโครไนซ์แอนิเมชันหลายรายการ: ตั้งค่า beginTime = CACurrentMediaTime() + offset เพื่อเริ่มกลุ่มแอนิเมชันด้วยหน่วงเวลาที่แม่นยำ CAMediaTiming ยังรองรับลำดับชั้นของเส้นเวลา — เลเยอร์แม่สามารถเร่ง/ชะลอแอนิเมชันลูกทั้งหมดผ่านคุณสมบัติ speed ใน UIKit UIViewPropertyAnimator (iOS 10+) ทำให้เส้นเวลาเป็นนามธรรมผ่านคุณสมบัติ duration, delay และ callbacks startAnimation/pauseAnimation/stopAnimation ใน SwiftUI โครงสร้าง Animation ให้ duration เป็นส่วนหนึ่งของข้อกำหนดแอนิเมชัน แต่การควบคุมเส้นเวลาโดยตรงถูกซ่อนไว้ — สำหรับเส้นเวลาแบบกำหนดเอง ให้ใช้ TimelineView (iOS 15+) พร้อมกับ scheduler ที่กำหนดเอง

Timeline ใน Android: Animator และ duration

ใน Android การจัดการเส้นเวลาถูกรวมศูนย์ในคลาส Animator และคลาสย่อย (ValueAnimator, ObjectAnimator) คุณสมบัติเส้นเวลาหลักคือ: duration (เป็นมิลลิวินาที), startDelay (หน่วงเวลาก่อนเริ่ม), repeatCount (จำนวนการทำซ้ำ), repeatMode (RESTART หรือ REVERSE) เมธอด setCurrentPlayTime(long) อนุญาตให้นำทางไปยังตำแหน่งใดๆ บนเส้นเวลา

ValueAnimator เพิ่มชั้นนามธรรม: มันสร้างค่าจาก 0 ถึง 1 (เวลาปกติ) ตาม duration และส่งต่อไปยัง TimeInterpolator AnimatorSet อนุญาตให้รวมหลาย Animator เข้าเป็นเส้นเวลาเดียวด้วยการดำเนินการตามลำดับ (playSequentially) หรือขนาน (playTogether) ใน Jetpack Compose เส้นเวลาถูกจัดการผ่าน AnimationSpec: tween (durationMillis, delayMillis, easing), spring (dampingRatio, stiffness) และ keyframes (จุดบนเส้นเวลาพร้อม easing ที่กำหนดเองสำหรับแต่ละส่วน) Compose AnimatedContent ใช้เส้นเวลาสำหรับ transitionSpec — นักพัฒนาอธิบายว่าเนื้อหาปรากฏ/หายไปอย่างไรพร้อมการเลื่อนเวลา ตาม Android Performance เส้นเวลาแอนิเมชันควรเป็นพหุคูณของ 16 ms (รอบ vsync) สำหรับ 60fps — ระยะเวลาที่ไม่ถูกต้องอาจทำให้เฟรมดรอปเนื่องจากการไม่สอดคล้องกับอัตรารีเฟรชของจอแสดงผล

การประกอบแอนิเมชันในช่วงเวลา

เส้นเวลามีความสำคัญเป็นพิเศษเมื่อประกอบแอนิเมชันหลายรายการ สามรูปแบบพื้นฐาน: แบบเรียงซ้อน (cascade) — แอนิเมชันเริ่มต้นตามลำดับโดยมีการเลื่อน (แต่ละอันถัดไปเริ่มต้นหลังจากออฟเซ็ตจากอันก่อนหน้า), แบบขนาน — แอนิเมชันทั้งหมดเริ่มต้นพร้อมกันด้วยเส้นเวลาเดียวกัน, และ แบบเหลื่อม (stagger) — แอนิเมชันเริ่มต้นโดยทับซ้อนกัน (อันที่สองเริ่มก่อนที่อันแรกจะเสร็จ)

ใน iOS การเรียงซ้อนถูกนำไปใช้ผ่าน beginTime ของแต่ละ CAAnimation = beginTime ก่อนหน้า + duration ก่อนหน้า สำหรับแบบเหลื่อม CAAnimationGroup ถูกใช้ด้วยค่า beginTime ที่แตกต่างกันในแอนิเมชันที่ซ้อนกัน ใน Android AnimatorSet รองรับ playSequentially และ playTogether; การเหลื่อมถูกสร้างขึ้นโดยการตั้งค่า startDelay สำหรับแต่ละ Animator ใน Compose AnimatedVisibility กับ enter/exitTransition ใช้การเหลื่อมในตัวแปร staggerChildren สำหรับการปรากฏแบบเรียงซ้อนของรายการรายการ ใน WWDC และ Google I/O 2024 ทั้งสองแพลตฟอร์มได้แนะนำเครื่องมือการแสดงภาพเส้นเวลา: Xcode Animations Inspector และ Android Studio Animations Timeline — พวกมันแสดงเส้นเวลาจริงและเฟรมที่ตกในเวลาจริง

ตัวอย่างโค้ด

iOS: CABasicAnimation กับ CAMediaTiming

ตัวอย่างแอนิเมชันที่มีเส้นเวลาแบบกำหนดเอง: หน่วงเวลา 0.3 วินาที, ระยะเวลา 0.6 วินาที, การกลับทิศอัตโนมัติ และการทำซ้ำไม่สิ้นสุด 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+) ให้การเข้าถึงเส้นเวลาของระบบสำหรับแอนิเมชันแบบกำหนดเอง View จะอัปเดตทุกครั้งที่ 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 กับ scheduler .periodic สร้างสัญญาณทุก 0.1 วินาที ใน closure context.date คือเวลาปัจจุบัน ซึ่งถูกแปลงเป็นเฟสคลื่นไซน์ ขนาดของวงกลมเต้นเป็นจังหวะที่ความถี่ 1 Hz TimelineView เป็นวิธีเดียวในการสร้างแอนิเมชันที่มีเส้นเวลาของตัวเองใน SwiftUI โดยไม่มี Animation API

Android: ValueAnimator พร้อมเส้นเวลาแบบกำหนดเอง

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 สำหรับการประกอบเส้นเวลา

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 ของตัวเอง — สิ่งนี้สร้างเอฟเฟกต์การเหลื่อม: fadeIn เริ่มก่อน (0 ms), slideUp หลังจาก 100 ms, scale หลังจาก 200 ms เส้นเวลาที่ได้: 0 — 100 — 200 — 600 ms สำหรับการดำเนินการตามลำดับ ให้ใช้ playSequentially

คำถามที่พบบ่อย

Animator แตกต่างจาก ValueAnimator ใน Android อย่างไร?

Animator คือ คลาสพื้นฐานนามธรรม สำหรับแอนิเมชันทั้งหมด ValueAnimator คือคลาสย่อยที่ทำให้ค่าตัวเลขเคลื่อนไหวโดยไม่ผูกกับวัตถุ ObjectAnimator (คลาสย่อยของ ValueAnimator) ทำให้คุณสมบัติเฉพาะของวัตถุเคลื่อนไหว (เช่น alpha หรือ translationY) สำหรับเส้นเวลา ให้ใช้ ValueAnimator เป็นตัวจับเวลาสากลพร้อม callback ผ่าน addUpdateListener

จะซิงโครไนซ์แอนิเมชันบนอุปกรณ์ต่างๆ ได้อย่างไร?

ใช้ นาฬิการะบบ (CACurrentMediaTime ใน iOS, System.nanoTime ใน Android) เพื่อคำนวณความคืบหน้า ไม่ใช่จำนวนเฟรม สำหรับการซิงโครไนซ์เครือข่าย ให้ใช้ตัวจับเวลาแบบ NTP พร้อมการแก้ไขออฟเซ็ต iOS รองรับ AVAudioSession สำหรับการซิงโครไนซ์เส้นเวลาเสียง-วิดีโอด้วยความแม่นยำระดับมิลลิวินาที หลีกเลี่ยงการซิงโครไนซ์ตามเฟรม — อัตราเฟรมแตกต่างกันตั้งแต่ 30 ถึง 120 fps

startOffset และ repeatCount ใน Animator คืออะไร?

startOffset คือหน่วงเวลาก่อนเริ่มแอนิเมชันเป็นมิลลิวินาที ใช้สำหรับเอฟเฟกต์แบบเรียงซ้อนและแบบเหลื่อม 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, หรือการใช้เส้นเวลาไม่ถูกต้อง (ระยะเวลาไม่เป็นพหุคูณของ 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 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ

ปรึกษาโครงการ

อ่านเพิ่มเติม