Timeline — 基础知识,应用程序中的动画时间管理

作者: IT Sectr 发布日期: 2026-03-02 阅读时间: 8 分钟
Timeline(时间线)— 动画的基本概念,决定了动画持续多长时间、各个阶段按什么顺序执行以及时间如何映射到进度上。在移动应用开发中,时间线通过持续时间(duration)、延迟(delay)、重复(repeat)和时间戳进行管理。在 iOS 中,动画时间线通过 CACurrentMediaTime 和 CAMediaTiming 实现,在 Android 中则通过 ValueAnimator 和 Animator 配合 duration、startDelay 和 repeatCount 参数实现。根据 Apple 文档,精确管理时间线对于动画同步至关重要:即使 16 毫秒(60fps 下的一帧)的不同步也会被用户感知为卡顿。在 IT Sectr,我们通过 Android 中的 ValueAnimator 和 iOS 中的 CABasicAnimation 配合 CAMediaTiming 标准化了时间线的使用——这确保了所有项目中统一的时间管理。

要点

  • 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] 中工作 — local time 或 progress。零值对应动画开始,一对应完成。缓动函数将线性 local time 转换为实际动画进度。如果 repeatCount > 1,时间线会循环重置(RESTART)或反转(REVERSE)。在 iOS 中,CAMediaTiming 添加了 speed(播放速度,>1 加速)和 timeOffset(时间线偏移)参数。在 Android 中,Animator 使用 setCurrentPlayTime() 直接控制时间线上的位置。根据 Material Design,短于 100 毫秒的动画不会被感知为动画,而长于 500 毫秒的动画则开始令人烦躁。界面动画的最佳持续时间是 200–350 毫秒。

iOS 中的 Timeline: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 属性和 startAnimation/pauseAnimation/stopAnimation 回调来抽象时间线。在 SwiftUI 中,Animation 结构提供 duration 作为动画规范的一部分,但时间线的直接控制是隐藏的——对于自定义时间线,请使用带有自己调度器的 TimelineView(iOS 15+)。

Android 中的 Timeline:Animator 和 duration

在 Android 中,时间线的管理集中在 Animator 类及其子类(ValueAnimator、ObjectAnimator)中。时间线的主要属性:duration(以毫秒为单位的持续时间)、startDelay(开始前的延迟)、repeatCount(重复次数)、repeatMode(RESTART 或 REVERSE)。setCurrentPlayTime(long) 方法允许沿时间线移动到任意位置。

ValueAnimator 增加了一个抽象层:基于 duration 生成从 0 到 1 的值(normalized time),并将它们传递给 TimeInterpolator。AnimatorSet 允许将多个 Animator 组合到单一时间线中,支持顺序(playSequentially)或并行(playTogether)执行。在 Jetpack Compose 中,时间线通过 AnimationSpec 管理:tween(durationMillis、delayMillis、easing)、spring(dampingRatio、stiffness)和 keyframes(时间线上的点,每个段都有自定义缓动)。Compose AnimatedContent 使用时间线进行 transitionSpec — 开发者描述内容如何随时间偏移出现/消失。根据 Android Performance,动画时间线应为 16 毫秒(vsync 周期)的倍数以保持 60fps — 错误的持续时间可能因与屏幕刷新率不匹配而导致丢帧。

动画的时间组合

时间线在组合多个动画时变得尤为重要。三种基本模式:级联 — 动画按顺序带偏移启动(每个后续在前一个偏移之后开始),并行 — 所有动画同时以相同时间线启动,交错 — 动画重叠启动(第二个在第一个完成之前开始)。

在 iOS 中,级联通过每个 CAAnimation 的 beginTime = 上一个 beginTime + 上一个 duration 实现。对于交错,使用 CAAnimationGroup 在嵌套动画中设置不同的 beginTime。在 Android 中,AnimatorSet 支持 playSequentially 和 playTogether;通过为每个 Animator 设置 startDelay 来创建交错效果。在 Compose 中,AnimatedVisibility 配合 enter/exitTransition 使用 staggerChildren 变体中的交错来实现列表元素的级联出现。在 WWDC 和 Google I/O 2024 上,两个平台都推出了时间线可视化工具:Xcode Animations Inspector 和 Android Studio Animations Timeline — 它们实时显示实际时间线和丢失的帧。

代码示例

iOS:带 CAMediaTiming 的 CABasicAnimation

自定义时间线动画示例:延迟 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 毫秒的延迟。autoreverses = true 使动画在每个周期后反向运行。repeatCount = .infinity 创建无限的"呼吸"效果循环。speed = 1.0 — 正常速度;用值 2.0 将动画加速 2 倍。

iOS:用于自定义时间线的 TimelineView

SwiftUI TimelineView(iOS 15+)提供对系统时间线的访问以进行自定义动画。视图在每次调度器计时时更新。

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 调度器每 0.1 秒生成一次计时。在闭包中,context.date — 当前时间,被转换为正弦波相位。圆的大小以 1 Hz 的频率脉动。TimelineView 是在没有 Animation API 的情况下在 SwiftUI 中创建具有自己时间线的动画的唯一方法。

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 毫秒 — 开始前的延迟。repeatMode = REVERSE 将动画返回到初始值。animatedFraction 提供从 0 到 1 的进度,同时考虑 repeatMode。addUpdateListener 每帧触发(通常为 16 毫秒)。要暂停,请使用 pause() / resume()。

Android:用于时间线组合的 AnimatorSet

AnimatorSet 允许从多个动画创建复杂的时间线。在示例中 — 带重叠的顺序执行(交错)。

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 毫秒),slideUp 在 100 毫秒后,scale 在 200 毫秒后。最终时间线:0 — 100 — 200 — 600 毫秒。对于顺序执行,请使用 playSequentially。

常见问题

Android 中 Animator 和 ValueAnimator 有什么区别?

Animator — 所有动画的抽象基类。ValueAnimator 是其子类,用于动画数值而不绑定到对象。ObjectAnimator(ValueAnimator 的后代)动画对象的特定属性(例如 alpha 或 translationY)。对于时间线,请使用 ValueAnimator 作为通用计时器,通过 addUpdateListener 进行回调。

如何在不同设备上同步动画?

使用系统时钟(iOS 中的 CACurrentMediaTime,Android 中的 System.nanoTime)计算进度,而不是帧数。对于网络同步,使用带偏移校正的基于 NTP 的计时器。iOS 支持 AVAudioSession 进行毫秒级精度的音视频时间线同步。避免基于帧的同步 — 帧率从 30 到 120 fps 不等。

Animator 中的 startOffset 和 repeatCount 是什么?

startOffset — 动画开始前的延迟(以毫秒为单位)。用于级联和交错效果。repeatCount — 重复次数:0 = 不重复,ValueAnimator.INFINITE = 无限循环。repeatMode 确定方向:RESTART(重置到开始)或 REVERSE(反向运动)。在 iOS 中,startOffset 称为 beginTime(与 CACurrentMediaTime 结合使用),repeatCount — CABasicAnimation 的同名属性。

动画的最佳持续时间是多少?

Material Design 建议界面动画使用 200–350 毫秒。短于 100 毫秒的动画不会被感知为动画,长于 500 毫秒的动画会令人烦躁。对于元素的进入/退出:200–300 毫秒。对于屏幕之间的过渡:300–400 毫秒。对小元素使用较短的持续时间(100–200 毫秒),对大元素使用较长的持续时间(400–500 毫秒)。

为什么动画在播放时卡顿?

卡顿(jank)由以下原因引起:主线程中的长时间操作(阻塞渲染)、带有过度绘制的复杂视图/图层层次结构、或时间线的不正确使用(持续时间不是 vsync 的倍数 — 60fps 为 16 毫秒,120fps 为 8 毫秒)。使用 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 进行直接控制。
  • Android 中的 AnimatorSet 和 iOS 中的 CAAnimationGroup 允许将动画组合到单一时间线中。
  • SwiftUI 中的 TimelineView(iOS 15+)无需 Animation API 即可访问系统调度器以创建自定义时间线。
  • iOS 中的 CACurrentMediaTime() 和 Android 中的 System.nanoTime — 用于动画同步的基本时间戳。
  • 根据 Material Design 和 HIG 建议,界面动画的最佳持续时间为 200-350 毫秒。

我们将开发一款交钥匙移动应用程序

IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。

讨论项目

另请阅读