SwiftUI中List搭配DragGesture无法正常滚动的问题求助
解决SwiftUI List与自定义按压反馈手势的滚动冲突问题
问题根源
你当前使用DragGesture(minimumDistance: 0)会拦截所有触摸事件,包括列表的滚动拖动——只要触摸位置发生哪怕微小移动,DragGesture就会触发并抢占事件优先级,导致List的滚动手势无法正常响应。之前尝试的onTapGesture和delaysTouches方案无效,正是因为DragGesture的优先级高于这些处理逻辑。
解决方案
改用PressGesture替代DragGesture,配合@GestureState跟踪按压状态:
- PressGesture仅在触摸未超过系统滚动阈值时保持活跃,用户开始滚动时会自动失效,不会干扰List的滚动手势。
@GestureState会在手势结束或取消时自动重置状态,无需手动处理状态回滚,更简洁可靠。
修改后的完整代码
struct TestView: View { @Environment(\.dismiss) var dismiss // 用GestureState跟踪当前按压的列表项,手势结束/取消时自动重置为nil @GestureState private var pressingNumber: Int? = nil var body: some View { ZStack { Color.blue .ignoresSafeArea() VStack { VStack(spacing: 10) { List { Section { ForEach(1...150, id: \.self) { number in HStack { Text("\(number)") .frame(maxWidth: .infinity, alignment: .leading) } .padding() .background(Color.red) .contentShape(Rectangle()) .buttonStyle(PlainButtonStyle()) .simultaneousGesture( PressGesture() // 更新GestureState标记当前按压的列表项 .updating($pressingNumber) { _, state, _ in state = number } // 按压结束时执行dismiss操作 .onEnded { _ in dismiss() } ) // 根据按压状态显示自定义覆盖层 .overlay( pressingNumber == number ? Color.primary.opacity(0.4) : nil ) } } .listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0)) .listRowSeparator(.visible) .listSectionSeparator(.hidden) } .listStyle(PlainListStyle()) Spacer() } } } } }
效果说明
- 列表滚动完全正常:用户拖动列表时,PressGesture自动失效,滚动手势正常接管。
- 自定义按压反馈:触摸列表项时立即显示半透明覆盖层,松开后覆盖层消失并执行页面dismiss。
- 无体验延迟:PressGesture的触发逻辑与系统手势兼容,不会出现触摸响应延迟。
内容的提问来源于stack exchange,提问作者kittonian
相关产品推荐
相关产品推荐

