SwiftUI中如何随时取消带延迟的withAnimation动画?
实现可取消的延迟动画任务
要实现支持随时取消的延迟动画,你需要用Swift的Task替代原来的DispatchQueue.main.asyncAfter——Task原生支持取消操作,能更方便地控制任务生命周期。以下是完整实现方案:
核心实现代码
import SwiftUI struct ContentView: View { @State private var opacity: Double = 1.0 // 持有任务引用,用于后续取消操作 @State private var delayedAnimationTask: Task<Void, Never>? var body: some View { VStack(spacing: 30) { // 演示动画的视图 Rectangle() .fill(.blue) .opacity(opacity) .frame(width: 200, height: 200) HStack(spacing: 20) { Button("启动任务") { startDelayedAnimation() } Button("取消任务") { cancelAnimationTask() } } .buttonStyle(.borderedProminent) } .padding() } // 启动延迟动画任务 private func startDelayedAnimation() { // 先清理旧任务,避免多个任务冲突 cancelAnimationTask() delayedAnimationTask = Task { do { // 等待5秒(转换为纳秒) try await Task.sleep(nanoseconds: 5_000_000_000) // 检查任务是否已取消,取消则终止后续操作 guard !Task.isCancelled else { return } // 执行3秒动画,将opacity设为0 withAnimation(.easeInOut(duration: 3)) { opacity = 0.0 } } catch { // 任务被取消时会抛出CancellationError,这里无需额外处理 } } } // 取消任务并重置状态 private func cancelAnimationTask() { delayedAnimationTask?.cancel() opacity = 1.0 delayedAnimationTask = nil } } #Preview { ContentView() }
关键细节说明
- 任务持有与管理:用
@State private var delayedAnimationTask: Task<Void, Never>?保存任务引用,这样能在任意时刻调用cancel()终止任务。 - 取消逻辑:调用
cancelAnimationTask()时,会立即终止任务(无论处于等待5秒还是动画执行阶段),同时将opacity重置为1。 - 任务冲突避免:启动新任务前先调用
cancelAnimationTask(),确保同一时间只有一个任务在运行,防止状态混乱。 - 取消检查:在等待5秒结束后,额外检查
Task.isCancelled,避免任务在等待期间被取消后仍执行动画。
内容的提问来源于stack exchange,提问作者Gregor Sotošek
相关产品推荐
相关产品推荐

