SwiftUI中使用PassthroughSubject实现防抖onTapGesture的更简化方案咨询
SwiftUI中使用PassthroughSubject实现防抖onTapGesture的更简化方案咨询
你好呀!看了你目前实现的带防抖功能的SwiftUI点击手势,确实原来的结构因为拆分了单独的DebounceViewModel类,显得有点冗余繁琐。其实我们可以通过合并逻辑、简化层级来让代码更清爽,这里给你两种更简洁的实现思路:
方案一:合并Combine逻辑到Modifier中(保留Combine依赖)
我们可以把原来ViewModel里的Subject和Cancellables直接内联到Modifier结构体中,去掉不必要的类嵌套,让逻辑更集中:
extension View { func onTapGesture(debounce: Double, action: @escaping () -> Void) -> some View { modifier(DebounceTapModifier(debounce: debounce, action: action)) } } struct DebounceTapModifier: ViewModifier { let debounce: Double let action: () -> Void private let subject = PassthroughSubject<Void, Never>() private var cancellables = Set<AnyCancellable>() init(debounce: Double, action: @escaping () -> Void) { self.debounce = debounce self.action = action setupDebounce() } func body(content: Content) -> some View { content .onTapGesture { subject.send() } } private func setupDebounce() { subject .debounce(for: .seconds(debounce), scheduler: DispatchQueue.main) .sink { _ in action() } .store(in: &cancellables) } }
这个版本去掉了单独的ViewModel类,把所有Combine相关的逻辑都放在Modifier内部,结构更紧凑,调用方式和你原来的完全一致,不需要修改任何调用代码。
方案二:用原生Timer实现(完全脱离Combine)
如果你的项目没有依赖Combine,或者想追求更轻量的实现,也可以用原生Timer手动管理防抖状态,代码会更直观:
extension View { func onTapGesture(debounce: Double, action: @escaping () -> Void) -> some View { modifier(DebounceTapTimerModifier(debounce: debounce, action: action)) } } struct DebounceTapTimerModifier: ViewModifier { let debounce: Double let action: @escaping () -> Void @State private var debounceTimer: Timer? func body(content: Content) -> some View { content .onTapGesture { // 每次点击先取消之前的定时器 debounceTimer?.invalidate() // 重新设置新的定时器 debounceTimer = Timer.scheduledTimer(withTimeInterval: debounce, repeats: false) { _ in action() } } } }
这个方案完全不需要Combine框架,通过@State管理定时器实例,每次点击时重置定时器,逻辑简单易懂,代码量也更少,非常适合简单的防抖需求。
总结
两种方案都保留了你原来的调用方式,不需要修改View中的调用代码:
Text("abc") .onTapGesture(debounce: 4) { print("done1") }
如果你的项目已经在使用Combine,方案一的简化版Combine实现足够清爽;如果想减少依赖,方案二的Timer实现是更轻量的选择,都比你原来的实现简化了不少层级。
内容来源于stack exchange
相关产品推荐
相关产品推荐

