You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 03:16:12