iOS UIAnimation异常行为:循环动画完成回调时机异常
解决UIView动画循环回调扎堆触发的问题
这个问题我做项目时也踩过坑!你遇到的情况核心原因很简单:你的for循环是同步执行的——它会在瞬间就把10个动画全部提交给Core Animation的动画队列,这些动画几乎是同时开始运行的(哪怕你设置了duration),所以它们会在同一时间结束,对应的完成回调自然就扎堆触发了。
正确的解决方案:让动画串行执行
要让每个动画的回调在对应动画结束时触发,我们需要让动画逐个执行——也就是前一个动画完成后,再启动下一个。最直观的实现方式是用递归:
// 定义一个递归动画函数 func animateViewStepByStep(currentCount: Int, totalTimes: Int, offset: CGFloat, duration: TimeInterval) { // 递归终止条件:已经完成所有动画 guard currentCount < totalTimes else { return } UIView.animate(withDuration: duration, animations: { // 更新视图位置 self.view.frame = CGRect( x: self.view.frame.origin.x, y: self.view.frame.origin.y - offset, width: self.view.frame.size.width, height: self.view.frame.size.height ) }) { [weak self] _ in // 当前动画完成,打印回调 print("loop completed -- \(currentCount)") // 启动下一次动画 self?.animateViewStepByStep(currentCount: currentCount + 1, totalTimes: totalTimes, offset: offset, duration: duration) } } // 调用这个函数开始动画 animateViewStepByStep(currentCount: 0, totalTimes: 10, offset: 你的偏移量数值, duration: 你的时长数值)
为什么这个方案有效?
- 递归函数会在前一个动画的
completion回调里才启动下一次动画,确保了动画是串行执行的,每个动画结束后才会触发下一个。 - 用
[weak self]避免了循环引用,防止内存泄漏。
如果你不想用递归,也可以用DispatchQueue的串行队列结合asyncAfter,但递归的写法更直观,也更贴合UI动画的回调逻辑。
内容的提问来源于stack exchange,提问作者krishan kumar
相关产品推荐
相关产品推荐

