iOS能否实现连续逐帧视图动画?有无web requestAnimationFrame同类接口?
iOS 屏幕刷新率同步逐帧动画实现方案
你需要的对标Web端Window.requestAnimationFrame()的原生逐帧回调能力,是Core Animation框架提供的CADisplayLink,它会在屏幕每一次硬件刷新前触发回调,和系统渲染管线完全同步,比Timer方案的稳定性、流畅度高很多,非常适合实现幸运大转盘这类需要精细控制的惯性动画。
基础使用方式
CADisplayLink需要注册到RunLoop中才能生效,使用时需要注意持有引用、计算真实帧间隔,示例代码如下:
import QuartzCore // 持有DisplayLink实例,避免被提前释放 private var displayLink: CADisplayLink? // 记录上一帧时间戳,用于计算真实帧间隔 private var lastFrameTimestamp: CFTimeInterval = 0 func startInertiaAnimation() { // 初始化DisplayLink,绑定帧回调 let link = CADisplayLink(target: self, selector: #selector(handleFrameTick(link:))) // 注册到主RunLoop的通用模式,避免滚动其他UI时动画被暂停 link.add(to: .main, forMode: .common) displayLink = link lastFrameTimestamp = CACurrentMediaTime() } @objc private func handleFrameTick(link: CADisplayLink) { // 计算当前帧与上一帧的真实时间差,不要硬编码1/60 let deltaTime = link.timestamp - lastFrameTimestamp lastFrameTimestamp = link.timestamp // 执行你的逐帧旋转更新逻辑 tickAnimation(deltaTime: deltaTime) // 动画结束(转盘停靠到目标位置)后必须手动终止回调 if isAnimationFinished { link.invalidate() displayLink = nil } }
对比Timer方案的核心优势
- 自动适配屏幕刷新率:在支持ProMotion的120Hz高刷屏设备上会自动匹配120fps的回调频率,动画流畅度远高于固定60fps的Timer方案
- 回调时机精准:回调触发时机和屏幕刷新完全对齐,不会出现Timer受主线程调度影响导致的掉帧、回调堆积问题
- 时间精度更高:通过内置的时间戳计算得到的帧间隔是真实值,做惯性减速计算时不会因为掉帧出现动画跳变、速度不均的问题,手感更自然
大转盘场景实现注意事项
- 不要手动修改
preferredFramesPerSecond属性,保持默认值0即可自动适配当前设备的最佳刷新率 - 绝对不要硬编码deltaTime为1/60,否则出现掉帧时转盘旋转速度会突然跳变,惯性效果会非常生硬
- 动画结束后必须调用
invalidate()终止回调,否则DisplayLink会持续持有绑定的target,造成内存泄漏,也会空耗CPU资源 - 如果需要更真实的物理减速效果,可以配合
UIDynamicAnimator自定义物理行为,不过如果要完全自主控制旋转停靠逻辑,CADisplayLink是灵活度最高的选择
内容的提问来源于stack exchange,提问作者sak
相关产品推荐
相关产品推荐

