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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 06:20:25