小米电池休眠自动解除 手机充不进电7个小妙招( 九 )


添加 CADisplayLink 至 CommonModes 中,分别在开始/停止滑动时启用/暂停 CADisplayLink,并修改对应的 preferredFramesPerSecond等属性,触发帧率变化 。CADisplayLink *dp = ...dp.paused = YES;[dp addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];CFRunLoopAddObserver(CFRunLoopGetMain(),CFRunLoopObserverCreateWithHandler(kCFAllocatorDefault, kCFRunLoopEntry | kCFRunLoopExit, YES, 0,^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {if (activity == kCFRunLoopEntry) {dp.paused = NO;dp.preferredFramePerSecond = 120;} else {dp.paused = YES;dp.preferredFramePerSecond = 0;}}), (__bridge CFStringRef)UITrackingRunLoopMode);在实践中 , 由于也存在需要在非滑动状态下解锁帧率上限的情况,所以方案 2 的通用性会更好 。
CAAnimation 设置动态帧率目前苹果只提供了修改 CAAnimation 动画帧率的 API,设置 CAAnimation.preferredFrameRateRange 即可改变其对屏幕刷新率的影响 。
对于用户感知明显的,如转场动画,可以设置为 120Hz 。对于感知不明显的,如旋转动画,可以降低其帧率,比如设置为 30Hz 。但是,和 DisplayLink 相同 , 过上述 API 的设置虽然会“影响”系统的动态帧率的选择,但这种影响并不是绝对的 。在实际使用中,笔者发现屏幕选择的刷新率和 CAAnimation 在屏幕上变化的速度有关 。
关于此点,以 iPhone 13 Pro 为例,笔者使用了一个简单的、偏好帧率为固定 120Hz 平移动画进行说明:
CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"transform.translation.y"];CGFloat speed = 170.0/330.0;anim.toValue = http://www.fzline.cn//sh/@(100);anim.fromValue = @(0);anim.duration = 10.0;anim.repeatCount = FLT_MAX;anim.preferredFrameRateRange = CAFrameRateRangeMake(120, 120, 120);其中 speed 变量为平移的速度 , 单位为 pt/s,试验发现:
speed 取 (0, 160] 时 , 屏幕刷新率为 60Hzspeed 取 [161, 320] 时,屏幕刷新率为 80Hzspeed 取 [321, +∞) 时,屏幕刷新率为 120Hz笔者仅在 iPhone 13 Pro 上测试了平移动画的场景,以上数据仅供参考 。
最后,对于其他的常见的动画 API,例如 UIView.animateWithDuration、UIViewPropertyAnimator 等,则没有提供对应 API 进行修改 。理论上也可以通过某些手段拿到这些上层 API 所创建的 CAAnimation 对象来实现修改 。
手势/转场等其他场景解锁 120Hz其他场景需要控制动态帧率的也可以通过手动修改 CADisplayLink 的 preferredFramePerSecond/preferredFrameRateRange 属性来实现,其实现和通过监听 RunLoop 来修改滑动帧率基本相同 。
UIGestureRecognizer 常被用于实现的交互式动画 。经过测试,发现在触发手势回调的同时启用一个解锁了频率的 CADisplayLink 也可以间接提高 UIGestureRecognizer 的回调频率,从而实现更高帧率的交互动画 。
对于转场的场景,一个简单的方案是 swizzle UIViewController 的生命周期消息,在出现/消失的节点启用/停用 CADisplayLink 帧率的解锁,从而实现通用的页面转场动画帧率解锁方案 。
Flutter 官方也计划提供类似 API 让应用侧可以针对不同的场景(滑动、动画 etc)动态切换屏幕刷新率:https://github.com/flutter/flutter/issues/90675
上线收益基于上述思路,笔者所在团队在国际化短视频业务落地了优化项目,经过实验验证:
大盘滑动帧率 P50 从 81.57 上升至 112.2核心业务指标也有一定收益结语近年来,Apple 生态中软硬件的发展日新月异,有软件层的 dyld 的持续优化和 iOS 15 新引入的 Prewarm 机制 , 也有新的 ProMotion 屏幕,可以看到 Apple 一直致力于打造更丝滑流畅的用户体验 。
Apple 提供的系统级优化方案一般通用而无感知,但通用往往也意味着一定的局限性,可能预留了额外优化空间,应用开发者们可以进一步去研究如何更好地适配 。

推荐阅读