You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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)")
                    }
                })
        )
    }
}

方案说明

  1. GestureState跟踪拖动方向:isHorizontalDrag会实时更新当前拖动是否为水平方向(x轴平移绝对值大于y轴)。
  2. 取消非水平拖动的手势识别:在updating方法中,如果判断为垂直拖动,设置transaction.isCancelled = true,让手势放弃事件拦截,垂直滚动事件会传递给List,恢复滚动功能。
  3. 仅处理水平拖动事件:在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 01:40:17