Swift中两个触发长动画的函数如何实现互相停止对方动画
两个触发长动画的函数互斥终止方案
核心逻辑很简单,不需要引入复杂的状态管理,用UIKit自带的动画终止接口,配合一个简单的运行状态标记就能实现。
实现步骤
- 首先定义枚举标记当前运行的动画类型,比用多个布尔值判断更不容易出状态冲突
- 每个函数触发时,第一步先终止所有正在运行的动画,把视图状态重置到初始位置,避免动画卡在中间帧
- 启动当前动画前更新状态标记,动画自然结束后清空标记即可
具体代码实现
首先给你的ViewController添加对应属性:
// 标记当前正在执行的动画类型 private enum RunningAnimation { case first, second, none } // 持有当前运行动画的状态,默认无运行中的动画 private var currentRunningAnim: RunningAnimation = .none // 替换成你实际执行动画的视图引用,多视图做动画就对应加多个引用 @IBOutlet weak var animationContainerView: UIView!
修改第一个函数的逻辑:
func firstFunc() { // 终止所有正在执行的动画 animationContainerView.layer.removeAllAnimations() // 如果之前运行的是第二个函数的动画,手动重置视图到初始状态 if currentRunningAnim == .second { animationContainerView.transform = .identity animationContainerView.alpha = 1 // 这里补全你第二个动画里修改过的所有视图属性,全部恢复为初始值 } Alert.show() // 更新状态标记为第一个动画运行中 currentRunningAnim = .first // 启动第一个长动画 UIView.animate(withDuration: 4, animations: { // 写你第一个动画的实际效果,比如位移、变色等 self.animationContainerView.center.x += 120 }, completion: { [weak self] isFinished in guard let self = self else { return } // 只有动画自然结束、没有被手动打断的时候才清空状态 if isFinished && self.currentRunningAnim == .first { self.currentRunningAnim = .none } }) }
修改第二个函数的逻辑:
func secondFunc() { // 终止所有正在执行的动画 animationContainerView.layer.removeAllAnimations() // 如果之前运行的是第一个函数的动画,手动重置视图到初始状态 if currentRunningAnim == .first { animationContainerView.transform = .identity animationContainerView.alpha = 1 // 这里补全你第一个动画里修改过的所有视图属性,全部恢复为初始值 } Alert.show() // 更新状态标记为第二个动画运行中 currentRunningAnim = .second // 启动第二个长动画 UIView.animate(withDuration: 4, animations: { // 写你第二个动画的实际效果,比如缩放、旋转等 self.animationContainerView.transform = CGAffineTransform(scaleX: 1.5, y: 1.5) }, completion: { [weak self] isFinished in guard let self = self else { return } // 只有动画自然结束、没有被手动打断的时候才清空状态 if isFinished && self.currentRunningAnim == .second { self.currentRunningAnim = .none } }) }
注意事项
- 必须用block形式的UIView动画接口,老版
beginAnimations/commitAnimations接口无法通过removeAllAnimations()可靠终止 - 调用
removeAllAnimations()后动画会直接停在当前中间帧,必须手动把所有动画修改的属性重置为初始值,否则下一个动画启动时会出现跳帧 - 完成回调里要判断
isFinished和当前状态标记再清空,避免被打断的旧动画回调误改新动画的运行状态 - 如果两个动画作用在不同视图上,只需要在函数开头对所有参与动画的视图都调用一次
layer.removeAllAnimations(),再对应重置状态即可
内容的提问来源于stack exchange,提问作者kesape
相关产品推荐
相关产品推荐

