Swift中如何通过Core Animation分组控制多视图多属性动画的暂停与恢复
在Swift中对Core Animation动画进行分组管理(同步、统一暂停/恢复)
需求背景
- 为多个子视图的多个属性添加Core Animation动画,需要实现:
- 动画同步执行
- 统一暂停/恢复所有动画
- 减少代码重复,保持代码简洁
- 尝试过
UIView.animate和UIViewPropertyAnimator,无法满足自定义动画需求 - 当前使用
CATransaction提交动画,运行正常,但统一控制动画的方式不够优雅且非原子性
解决方案
方案1:使用容器图层(最优解)
通过创建一个容器CALayer,将所有需要执行动画的视图图层添加到该容器中,只需控制容器图层的动画属性,就能统一管理所有子图层的动画,实现原子性控制。
步骤1:初始化容器图层并添加子图层
// 初始化容器图层,设置与父视图一致的frame let animationContainerLayer = CALayer() animationContainerLayer.frame = view.bounds view.layer.addSublayer(animationContainerLayer) // 将需要动画的视图图层添加到容器中 animationContainerLayer.addSublayer(label.layer) animationContainerLayer.addSublayer(imageView.layer)
步骤2:添加动画(保持CATransaction同步)
CATransaction.begin() CATransaction.setAnimationDuration(1.5) CATransaction.setAnimationTimingFunction(CAMediaTimingFunction(controlPoints: 0.85, 0, 0.15, 1)) // 透明度动画 let opacityAnimation = CABasicAnimation(keyPath: "opacity") opacityAnimation.fromValue = 0 opacityAnimation.toValue = 1.0 opacityAnimation.repeatCount = .infinity opacityAnimation.autoreverses = true label.layer.add(opacityAnimation, forKey: "opacityAnimation") // 缩放动画 let scaleAnimation = CABasicAnimation(keyPath: "transform.scale") scaleAnimation.fromValue = 1.5 scaleAnimation.toValue = 1.0 scaleAnimation.repeatCount = .infinity scaleAnimation.autoreverses = true imageView.layer.add(scaleAnimation, forKey: "scaleAnimation") CATransaction.commit()
步骤3:统一暂停/恢复动画
只需修改容器图层的属性,所有子图层的动画会同步响应:
// 暂停所有动画 func pauseAllAnimations() { let pausedTime = animationContainerLayer.convertTime(CACurrentMediaTime(), from: nil) animationContainerLayer.speed = 0.0 animationContainerLayer.timeOffset = pausedTime } // 恢复所有动画 func resumeAllAnimations() { let pausedTime = animationContainerLayer.timeOffset animationContainerLayer.speed = 1.0 animationContainerLayer.timeOffset = 0.0 animationContainerLayer.beginTime = 0.0 let timeSincePause = animationContainerLayer.convertTime(CACurrentMediaTime(), from: nil) - pausedTime animationContainerLayer.beginTime = timeSincePause }
方案2:CATransaction包裹遍历操作(兼容现有图层结构)
如果无法调整图层层级结构,可将遍历修改图层属性的操作放入CATransaction中,确保所有变更原子性提交,避免状态不一致。
// 统一暂停动画 func pauseAllAnimations() { CATransaction.begin() CATransaction.setDisableActions(true) // 禁用图层属性变更的隐式动画 let targetLayers = [label.layer, imageView.layer] for layer in targetLayers { let pausedTime = layer.convertTime(CACurrentMediaTime(), from: nil) layer.speed = 0.0 layer.timeOffset = pausedTime } CATransaction.commit() } // 统一恢复动画 func resumeAllAnimations() { CATransaction.begin() CATransaction.setDisableActions(true) let targetLayers = [label.layer, imageView.layer] for layer in targetLayers { let pausedTime = layer.timeOffset layer.speed = 1.0 layer.timeOffset = 0.0 layer.beginTime = 0.0 let timeSincePause = layer.convertTime(CACurrentMediaTime(), from: nil) - pausedTime layer.beginTime = timeSincePause } CATransaction.commit() }
注意事项
- 容器图层方案更简洁高效,推荐优先使用
- 原代码中存在变量名错误:
beforeOpacityAnimation应为opacityAnimation,targetImageScaleAnimation应为scaleAnimation,需修正避免编译报错
内容的提问来源于stack exchange,提问作者MiZioLi5
相关产品推荐
相关产品推荐

