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

Swift中如何删除CABasicAnimation后再重新启动该动画?

问题核心原因

  • 你当前每次调用showAnimatingDotsInImageView(true)都会创建全新的CAReplicatorLayer实例并添加到dots.layer上,多次调用自然会出现动画叠加的问题
  • 调用showAnimatingDotsInImageView(false)时直接把dots从父视图移除了,后续没有逻辑把dots重新加回父视图,所以再调用true也看不到动画

实现方案

我们把动画相关的层和初始化逻辑提到全局,避免重复创建,同时仅控制动画的启停/层的显隐,不要随意移除dots视图本身:

  1. 将CAReplicatorLayer和动画圆点层改为ViewController的全局属性,初始化逻辑只执行一次
  2. 调用false时直接移除动画、清除动画层;调用true时先判断是否已经存在动画层,避免重复添加,再重启动画

修改后的完整代码

class ViewController: UIViewController {
    // some code
    let dots = UIImageView()
    // 把动画相关资源提为全局属性,避免重复创建
    private let replicatorLayer = CAReplicatorLayer()
    private let dotLayer = CALayer()
    private let dotAnimation = CABasicAnimation(keyPath: #keyPath(CALayer.opacity))

    override func viewDidLoad() {
        super.viewDidLoad()

        // some code
        dots.translatesAutoresizingMaskIntoConstraints = false
        dots.backgroundColor = .red
        dots.center = self.view.center
        view.addSubview(dots)
        // Some Auto Layout code
        
        // 动画配置只执行一次,不要每次调用函数都重复创建
        setupAnimationLayers()
    }

    // 单独抽离动画初始化逻辑
    private func setupAnimationLayers() {
        replicatorLayer.frame = CGRect(x: -55, y: 0, width: 30, height: 14)
        dotLayer.frame = CGRect(x: 10, y: 10, width: 10, height: 10)
        dotLayer.cornerRadius = dotLayer.frame.width / 2
        dotLayer.backgroundColor = rocketDark.cgColor
        replicatorLayer.addSublayer(dotLayer)
        replicatorLayer.instanceCount = 5
        replicatorLayer.instanceTransform = CATransform3DMakeTranslation(20, 0, 0)
        
        dotAnimation.fromValue = 0.0
        dotAnimation.toValue = 1.0
        dotAnimation.duration = 2
        dotAnimation.repeatCount = .infinity
        replicatorLayer.instanceDelay = dotAnimation.duration / Double(replicatorLayer.instanceCount)
    }

    func showAnimatingDotsInImageView(_ isOn: Bool) {
        if isOn {
            // 先判断是否已经添加过动画层,避免重复叠加
            if replicatorLayer.superlayer == nil {
                dots.layer.addSublayer(replicatorLayer)
            }
            // 重启动画、显示视图
            dotLayer.add(dotAnimation, forKey: "dotOpacityAnimation")
            dots.isHidden = false
        } else {
            // 移除动画和层,隐藏视图即可,不需要把dots从父视图删除
            dotLayer.removeAnimation(forKey: "dotOpacityAnimation")
            replicatorLayer.removeFromSuperlayer()
            dots.isHidden = true
        }
    }
}

调用方式

直接按你原有逻辑调用即可:

  • 需要展示动画时调用showAnimatingDotsInImageView(true)
  • 需要停止隐藏动画时调用showAnimatingDotsInImageView(false)

内容的提问来源于stack exchange,提问作者pawCheese

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 18:06:08