Swift UIKit:如何让顺序动画函数循环执行N次?
问题
现有一个upDown()函数,通过UIView.animate实现两个ImageView的上下脉冲动画(分别重复4次和2次),运行正常。但需要让整个upDown()的动画流程按顺序循环执行指定次数(如5次或25次)。尝试过用其他UIView.animate包裹、for-in循环均未成功,项目禁止使用Pods,需要找到可行的原生实现方案。
现有代码:
func upDown() { runButton.isEnabled = false UIView.animate( withDuration: 0.5, delay: 0, options: [.autoreverse, .repeat]) { UIView.modifyAnimations(withRepeatCount: 4, autoreverses: true) { self.arrowDownImageView.transform = CGAffineTransform(scaleX: 1.3, y: 1.3) self.arrowDownImageView.tintColor = .green self.downLabel.backgroundColor = .green } } completion: { _ in self.arrowDownImageView.transform = .identity self.downLabel.transform = .identity self.downLabel.backgroundColor = .black self.arrowDownImageView.tintColor = .black UIView.animate( withDuration: 0.5, delay: 0, options: [.autoreverse, .repeat]) { UIView.modifyAnimations(withRepeatCount: 2, autoreverses: true) { self.arrowUpImageView.transform = CGAffineTransform(scaleX: 1.3, y: 1.3) self.arrowUpImageView.tintColor = .blue self.upLabel.backgroundColor = .blue } } completion: { _ in self.arrowUpImageView.transform = .identity self.upLabel.transform = .identity self.upLabel.backgroundColor = .black self.arrowUpImageView.tintColor = .black self.runButton.isEnabled = true } } }
解决方案
核心思路是把单次完整的上下动画流程(down动画→up动画)封装成独立方法,通过计数器+递归调用适配动画的异步特性,实现指定次数的循环。
步骤1:封装单次完整动画流程
将原来upDown()里的逻辑抽成带完成回调的方法,明确单次动画流程的结束时机:
func runSingleUpDownCycle(completion: @escaping () -> Void) { // 执行down动画 UIView.animate( withDuration: 0.5, delay: 0, options: [.autoreverse, .repeat]) { UIView.modifyAnimations(withRepeatCount: 4, autoreverses: true) { self.arrowDownImageView.transform = CGAffineTransform(scaleX: 1.3, y: 1.3) self.arrowDownImageView.tintColor = .green self.downLabel.backgroundColor = .green } } completion: { _ in // 重置down控件状态 self.arrowDownImageView.transform = .identity self.downLabel.transform = .identity self.downLabel.backgroundColor = .black self.arrowDownImageView.tintColor = .black // 执行up动画 UIView.animate( withDuration: 0.5, delay: 0, options: [.autoreverse, .repeat]) { UIView.modifyAnimations(withRepeatCount: 2, autoreverses: true) { self.arrowUpImageView.transform = CGAffineTransform(scaleX: 1.3, y: 1.3) self.arrowUpImageView.tintColor = .blue self.upLabel.backgroundColor = .blue } } completion: { _ in // 重置up控件状态 self.arrowUpImageView.transform = .identity self.upLabel.transform = .identity self.upLabel.backgroundColor = .black self.arrowUpImageView.tintColor = .black // 单次流程完成,触发回调 completion() } } }
步骤2:实现带循环次数的控制方法
新增方法接收循环次数参数,通过递归调用单次动画方法,直到完成指定次数:
func runUpDownLoop(totalCycles: Int) { runButton.isEnabled = false var completedCycles = 0 func executeNextCycle() { completedCycles += 1 runSingleUpDownCycle { [weak self] in guard let self = self else { return } if completedCycles < totalCycles { // 未完成所有次数,继续下一轮 executeNextCycle() } else { // 所有循环结束,恢复按钮状态 self.runButton.isEnabled = true } } } // 启动第一次循环 executeNextCycle() }
步骤3:调用方式
直接调用runUpDownLoop(totalCycles: 5)即可让整个动画流程循环5次,替换原来的upDown()调用即可。
补充说明
- 使用
[weak self]避免循环引用,防止内存泄漏 - 递归调用天然适配动画的异步特性,确保每一轮动画都在上一轮完全结束后才开始
- 计数器
completedCycles准确跟踪循环进度,完成指定次数后自动停止并恢复交互状态
内容的提问来源于stack exchange,提问作者Zenit
相关产品推荐
相关产品推荐

