Swift中如何删除CABasicAnimation后再重新启动该动画?
问题核心原因
- 你当前每次调用
showAnimatingDotsInImageView(true)都会创建全新的CAReplicatorLayer实例并添加到dots.layer上,多次调用自然会出现动画叠加的问题 - 调用
showAnimatingDotsInImageView(false)时直接把dots从父视图移除了,后续没有逻辑把dots重新加回父视图,所以再调用true也看不到动画
实现方案
我们把动画相关的层和初始化逻辑提到全局,避免重复创建,同时仅控制动画的启停/层的显隐,不要随意移除dots视图本身:
- 将
CAReplicatorLayer和动画圆点层改为ViewController的全局属性,初始化逻辑只执行一次 - 调用
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
相关产品推荐
相关产品推荐

