iOS应用回到前台后如何恢复已停止的UIView旋转动画?
问题原因
两种场景的系统行为有本质区别:
- 打开控制中心/通知中心时,应用仅进入
UIApplicationInactive(非活跃)状态,没有被切换到后台,系统不会移除当前正在执行的UIView动画,因此返回应用后动画会正常继续。 - 切到后台/锁屏时,应用进入
UIApplicationBackground(后台)状态,系统会主动清理所有附着在视图layer上的动画对象,此时你之前对layer做的暂停状态配置也会失效,因此回到前台后动画就停止了。
修复方案
你需要在进入后台时记录当前动画的实际执行进度,回到前台时重新创建动画并承接之前的进度,修改步骤如下:
- 新增变量存储当前旋转的真实角度,避免动画中断后角度跳变
// 存储当前旋转的真实弧度 var currentRotation: CGFloat = 0
- 修改旋转动画方法,统一基于
currentRotation计算旋转状态
func rotateImageView() { vinylStatus = "true" UIView.animate(withDuration: 3, delay: 0, options: .curveLinear, animations: { self.currentRotation += .pi / 2 self.vinylView.transform = CGAffineTransform(rotationAngle: self.currentRotation) }) { (finished) in if finished { self.rotateImageView() } } }
- 完善通知回调的逻辑,进入后台时记录进度,回到前台时重启动画
@objc func applicationDidBecomeActive(notification: NSNotification) { print("applicationDidBecomeActive") guard vinylStatus == "true" else { return } // 先将视图设置为切后台时的最终角度,避免画面跳变 vinylView.transform = CGAffineTransform(rotationAngle: currentRotation) // 重新启动旋转动画 rotateImageView() resumeLayer(layer: vinylView.layer) } @objc func applicationDidEnterBackground(notification: NSNotification) { guard vinylStatus == "true" else { return } pauseLayer(layer: vinylView.layer) // 从layer的presentation层获取当前真实展示的旋转角度,更新存储值 if let presentationLayer = vinylView.layer.presentation() { currentRotation = atan2(presentationLayer.transform.m12, presentationLayer.transform.m11) } }
优化建议
你当前使用字符串类型的vinylStatus标记动画状态,建议改为Bool类型var isAnimating: Bool = false,避免字符串拼写错误导致的逻辑异常。
内容的提问来源于stack exchange,提问作者user8702799
相关产品推荐
相关产品推荐

