iOS 18中添加高优先级拖动手势致可滚动视图无法滚动的解决办法咨询
解决iOS 18中List添加水平拖动手势后无法滚动的问题
问题原因
iOS 18 beta版本中highPriorityGesture的事件拦截逻辑发生了变化:默认的DragGesture会捕获所有方向的拖动事件(包括垂直方向),导致List的垂直滚动事件被完全拦截,无法正常滚动。而iOS 17及更早版本中,系统会自动区分拖动方向,让垂直滚动事件透传给List。
可行解决方案
核心思路是让拖动手势仅响应水平方向的拖动,垂直方向的拖动事件直接透传给List处理。可以通过GestureState结合手势的updating方法判断拖动方向,非水平拖动时取消手势识别,具体代码如下:
struct ContentView: View { // 跟踪当前是否为水平拖动 @GestureState private var isHorizontalDrag = false var body: some View { List { ForEach(0..<100) { Text("\($0)") } } .highPriorityGesture( DragGesture(minimumDistance: 5) // 更新手势状态,判断是否为水平拖动,非水平则取消手势 .updating($isHorizontalDrag) { value, state, transaction in state = abs(value.translation.width) > abs(value.translation.height) if !state { transaction.isCancelled = true } } .onChanged({ value in if isHorizontalDrag { print("onChanged \(value)") } }) .onEnded({ value in if isHorizontalDrag { print("onEnded \(value)") } }) ) } }
方案说明
GestureState跟踪拖动方向:isHorizontalDrag会实时更新当前拖动是否为水平方向(x轴平移绝对值大于y轴)。- 取消非水平拖动的手势识别:在
updating方法中,如果判断为垂直拖动,设置transaction.isCancelled = true,让手势放弃事件拦截,垂直滚动事件会传递给List,恢复滚动功能。 - 仅处理水平拖动事件:在
onChanged和onEnded中,只有当isHorizontalDrag为true时才执行逻辑,确保水平拖动的优先级仍高于滚动。
另一种简化方案
如果不需要严格的优先级控制,也可以使用simultaneousGesture配合方向判断,这种方式下水平拖动和垂直滚动可能会同时触发,适合不需要严格拦截滚动的场景:
struct ContentView: View { var body: some View { List { ForEach(0..<100) { Text("\($0)") } } .simultaneousGesture( DragGesture(minimumDistance: 5) .onChanged({ value in if abs(value.translation.width) > abs(value.translation.height) { print("onChanged \(value)") } }) .onEnded({ value in if abs(value.translation.width) > abs(value.translation.height) { print("onEnded \(value)") } }) ) } }
内容的提问来源于stack exchange,提问作者Toru
相关产品推荐
相关产品推荐

