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

如何让SwiftUI中ScrollView的LongPressGesture与滚动功能共存?

解决ScrollView长按元素时滚动失效的问题

问题出在使用.simultaneousGesture(longTap)时,长按手势会和ScrollView的拖动手势同时触发,干扰了滚动的手势识别逻辑,导致滚动失效。

可以通过将长按手势与拖动手势进行序列处理来解决,让SwiftUI先识别长按操作,若后续出现拖动则切换为滚动,既保留长按的实时状态更新,又不影响滚动功能:

import SwiftUI

struct TextBox: View {
  var text: String
  var color: Color
  @GestureState private var isLongPressure: Bool = false
  
  var body: some View {
    // 组合长按手势与拖动手势,形成序列
    let longPressThenDrag = LongPressGesture(minimumDuration: 0.3)
      .updating($isLongPressure) { state, newState, transaction in
        newState = state
        transaction.animation = .easeOut(duration: 0.2)
      }
      // 长按后如果触发拖动,就结束长按状态
      .sequenced(before: DragGesture())
      .onEnded { value in
        // 确保长按结束后状态重置
        if case .second(_, nil) = value {
          isLongPressure = false
        }
      }
    
    Text(text)
      .frame(width: 400, height: 200)
      .background(isLongPressure ? .white : color)
      // 使用普通的gesture修饰符,替代simultaneousGesture
      .gesture(longPressThenDrag)
  }
}

struct TestGestures: View {
    var body: some View {
      ScrollView {
        TextBox(text: "Test 1", color: .red)
        TextBox(text: "Test 2", color: .green)
        TextBox(text: "Test 3", color: .blue)
        TextBox(text: "Test 4", color: .red)
        TextBox(text: "Test 5", color: .green)
        TextBox(text: "Test 6", color: .blue)
      }
    }
}

struct TestGestures_Previews: PreviewProvider {
    static var previews: some View {
        TestGestures()
    }
}

原理说明

  • sequenced(before: DragGesture()) 让手势识别分为两步:先尝试识别长按,若长按过程中用户开始拖动,则切换到拖动手势(即ScrollView的滚动),同时结束长按状态。
  • 替换.simultaneousGesture为普通.gesture,避免两个手势同时抢占事件,让SwiftUI按照序列逻辑处理手势优先级。

这样修改后,长按元素时会正常触发背景色变化,拖动时ScrollView也能正常滚动,两者互不干扰。

内容的提问来源于stack exchange,提问作者Ivan Pomortsev

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 08:59:19