SwiftUI动画结束时如何调用完成闭包?
在SwiftUI中监听动画完成事件
SwiftUI的.animation视图修饰器本身确实没有提供直接的完成回调入口,但可以通过以下几种方式实现类似UIKit中animate方法的完成闭包效果:
1. 优先使用iOS 15+原生API
从iOS 15、macOS 12及以上版本开始,SwiftUI新增了带完成回调的withAnimation方法,这是最简洁的解决方案:
// 修改状态触发动画,并绑定完成回调 withAnimation(.easeInOut(duration: animationDurationOffsetX)) { xOffset = yourTargetOffsetValue } completion: { // 动画结束后执行的逻辑 print("动画已完成") // 这里可以写入自定义处理代码 }
2. 自定义修饰器兼容旧版本(iOS 13+)
如果需要适配iOS 13及更早版本,可以自定义一个视图修饰器来监听动画属性的完成状态:
// 自定义动画完成监听修饰器 struct AnimationCompletionObserver: AnimatableModifier { private let targetValue: CGFloat private let completion: () -> Void var animatableData: CGFloat { didSet { checkCompletion() } } init(targetValue: CGFloat, completion: @escaping () -> Void) { self.targetValue = targetValue self.completion = completion self.animatableData = targetValue } private func checkCompletion() { guard animatableData == targetValue else { return } DispatchQueue.main.async { completion() } } func body(content: Content) -> some View { content } } // 给View添加便捷调用方法 extension View { func onAnimationCompleted<Value: VectorArithmetic>(for value: Value, completion: @escaping () -> Void) -> some View { modifier(AnimationCompletionObserver( targetValue: value.magnitude as! CGFloat, completion: completion )) } }
使用示例:
YourView() .offset(x: xOffset) .animation(.easeInOut(duration: animationDurationOffsetX), value: xOffset) .onAnimationCompleted(for: xOffset) { print("动画完成回调触发") }
3. 简单场景用延迟执行(不推荐复杂场景)
如果动画时长固定且不会被中断,可以直接用延迟执行模拟完成回调:
// 修改状态触发动画 xOffset = yourTargetOffsetValue // 延迟动画时长后执行完成逻辑 DispatchQueue.main.asyncAfter(deadline: .now() + animationDurationOffsetX) { print("动画完成") }
注意:这种方法不够精确,若动画被系统打断或时长变化,回调时机会出错,仅适合简单测试场景。
内容的提问来源于stack exchange,提问作者Frank Marx
相关产品推荐
相关产品推荐

