SwiftUI:如何合并连续点击事件,实现提示框延迟消失
解决方案
你的问题根源在于:原代码中使用DispatchQueue.main.asyncAfter提交的延迟任务,不会随着.task(id:)的取消而终止。当快速切换按钮时,前一个按钮触发的asyncAfter任务仍会在3秒后执行,将tipText设为nil,导致新显示的提示被提前关闭。
最优的实现方式是改用SwiftUI原生的Task.sleep,它能响应.task(id:)的取消操作,确保只有当前激活的延迟任务会执行:
struct SwiftUIView: View { @State var tipText: String? var body: some View { ZStack { VStack { HStack { Button("Red") { tipText = "Red" } .tint(.red) .controlSize(.large) .buttonStyle(.borderedProminent) Button("Blue") { tipText = "Blue" } .tint(.blue) .controlSize(.large) .buttonStyle(.borderedProminent) } Spacer() } .padding() if let tipText = tipText { Text( """ You have just clicked the \(tipText) button, this prompt will disappear in 3 seconds. """ ) .padding() .background(.ultraThickMaterial) .cornerRadius(10) .task(id: tipText) { // 等待3秒,任务被取消时会终止等待 try? await Task.sleep(nanoseconds: 3_000_000_000) // 回到主线程更新状态 await MainActor.run { self.tipText = nil } } } } } }
原理说明
.task(id: tipText)会在tipText变化时自动取消之前的任务,启动新任务Task.sleep是可取消的异步等待,当任务被取消时会立即终止,不会执行后续的tipText = nil- 使用
await MainActor.run确保状态更新在主线程执行,符合SwiftUI的线程安全要求
这样无论用户连续点击多少次按钮,每次点击都会重置延迟计时,只有最后一次点击后等待3秒,提示才会消失。
内容的提问来源于stack exchange,提问作者ylqylq001
相关产品推荐
相关产品推荐

