IBAnimatable 动画队列管理:链式调用与 completion 回调
你是否还在为 iOS 动画的顺序执行和回调处理而烦恼?IBAnimatable 通过 AnimationPromise 和 AnimationChainable 协议提供了优雅的解决方案,让复杂动画队列像搭积木一样简单。本文将详解如何通过链式调用编排动画序列,并精准控制每个动画的完成回调。
核心原理:动画队列的数据结构
IBAnimatable 的动画队列基于 AnimationPromise 类实现,其核心数据结构定义在 Sources/Others/AnimationChainable.swift 中:
public class AnimationPromise<T: UIView> where T: Animatable {
private var view: T
private var animationList = [AnimationTuple]() // 存储动画元组队列
private var completion: AnimatableCompletion? // 队列完成回调
}
每个动画元组包含动画类型和配置信息:
typealias AnimationTuple = (type: AnimationType, configuration: AnimationConfiguration)
struct AnimationConfiguration {
let damping: CGFloat // 弹性阻尼
let velocity: CGFloat // 初始速度
let duration: TimeInterval // 持续时间
let delay: TimeInterval // 延迟时间
let force: CGFloat // 动画强度
let timingFunction: TimingFunctionType // 时间曲线
}
链式调用:构建动画序列
通过 then() 方法可将动画按顺序添加到队列,支持链式语法:
// 示例:按钮点击后的动画序列
button.animate(.pop(repeatCount: 1))
.then(.slide(.in, direction: .left), duration: 0.5)
.delay(0.3) // 延迟0.3秒执行下一个动画
.then(.fade(.out), damping: 0.7)
.completion {
print("所有动画执行完毕")
}
关键方法解析
-
animate()启动队列
在 Sources/Protocols/Animatable/Animatable.swift 中定义:@discardableResult func animate(_ animation: AnimationType) -> AnimationPromise<Self> { return AnimationPromise(view: self).delay(delay).then(animation) } -
then()添加动画
每次调用会创建新的动画元组并加入队列:public func then(_ animation: AnimationType, duration: TimeInterval? = nil) -> AnimationPromise { let config = AnimationConfiguration( damping: damping ?? view.damping, duration: duration ?? view.duration, // 其他配置参数... ) animationList.append((animation, config)) return self // 返回自身实现链式调用 }
回调机制:监控动画生命周期
单个动画完成回调
每个动画执行完毕后通过 promise.animationCompleted() 触发队列推进:
func animationCompleted() {
animationList.removeFirst() // 移除已完成动画
if let nextAnimation = animationList.first {
view.doAnimation(nextAnimation.type, configuration: nextAnimation.configuration, promise: self)
} else {
completion?() // 所有动画完成,触发最终回调
}
}
队列完成回调
通过 completion() 方法设置整个队列的结束处理:
public func completion(_ completion: AnimatableCompletion?) {
self.completion = completion
}
高级应用:并行动画与复合动画
并行执行多个动画
使用 .compound 动画类型可在一个步骤中并行执行多个动画:
button.animate(.compound([.scale(1,1,1.5,1.5), .rotate(.cw, repeatCount: 1)], run: .parallel))
.then(.fade(.out), duration: 0.3)
复杂序列控制
结合延迟和并行动画创建更复杂的交互效果:
// 登录表单加载动画
usernameField.animate(.slide(.in, direction: .right), duration: 0.4)
passwordField.delay(0.1).animate(.slide(.in, direction: .right), duration: 0.4)
loginButton.delay(0.2).animate(.zoom(.in), duration: 0.5)
实战案例:购物车添加动效
以下是商品添加到购物车的完整动画序列实现:
func addToCartAnimation(for productView: UIView, cartButton: UIButton) {
// 1. 商品缩放并淡出
productView.animate(.compound([
.scale(1,1,0.5,0.5),
.fade(.out)
], run: .parallel), duration: 0.3)
.completion {
// 2. 购物车按钮弹跳提示
cartButton.animate(.pop(repeatCount: 2), duration: 0.6)
}
}
性能优化建议
- 避免过度动画:同时执行不超过3个并行动画
- 重用配置:通过
AnimationConfiguration共享常用参数 - 及时清理:复杂场景下调用
stopAnimations()避免内存泄漏
总结与最佳实践
IBAnimatable 的动画队列管理通过链式调用和回调机制,大幅简化了复杂动画序列的实现。核心优势包括:
- 代码可读性:链式语法直观反映动画执行顺序
- 灵活性:支持串行/并行混合编排
- 精确控制:完善的生命周期回调机制
建议在实际开发中:
- 将常用动画序列封装为扩展方法
- 复杂交互使用
AnimationPromise手动管理队列 - 始终在
completion中处理后续业务逻辑
完整实现细节可参考:
通过这些工具,你可以轻松实现丝滑流畅的iOS交互动画,提升用户体验的同时保持代码的可维护性。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



