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

SwiftUI拖拽优先触发时阻塞UIKit UITouch的多点触控问题求助

解决SwiftUI与UIKit多点触控交互阻塞问题

问题场景

在UIView绘图表面叠加SwiftUI控件的多点触控场景中:

  • 先触发UIKit触摸(红色方块外拖拽),再操作SwiftUI控件(红色方块内拖拽):两者均可正常响应触摸事件
  • 先触发SwiftUI拖拽手势(红色方块内拖拽),再操作UIKit区域(红色方块外拖拽):UIKit的UITouch事件被完全阻塞,仅能收到SwiftUI的触摸日志

问题原因

SwiftUI的DragGesture默认以.first模式独占触摸事件(第一个激活的手势会拦截所有后续触摸,阻止底层视图接收事件),导致先触发SwiftUI手势时,底层UIView无法获取其他手指的触摸信号。

解决方案

修改SwiftUI的DragGesture初始化参数,将独占模式改为.never,允许手势与其他触摸事件同时响应:

.gesture(DragGesture(minimumDistance: 0, exclusively: .never)
    .updating($touchXY) { (value, touchXY, _) in 
        touchXY = value.location
    })

完整修改后的代码

import SwiftUI
struct ContentView: View {
    @GestureState private var touchXY: CGPoint = .zero
    var body: some View {
        ZStack {
            TouchRepresentable()
            Rectangle()
                .foregroundColor(.red)
                .frame(width: 128, height: 128)
                .gesture(DragGesture(minimumDistance: 0, exclusively: .never)
                    .updating($touchXY) { (value, touchXY, _) in 
                        touchXY = value.location
                    })
                .onChange(of: touchXY) {
                    print(String(format:"SwiftUI(%.2g,%.2g)", $0.x,$0.y), terminator: " ") 
                }
        }
    }
}
struct TouchRepresentable: UIViewRepresentable {
    typealias Context = UIViewRepresentableContext<TouchRepresentable>
    public func makeUIView(context: Context) -> TouchView { 
        return TouchView() 
    }
    public func updateUIView(_ uiView: TouchView, context: Context) {}
}
class TouchView: UIView {
    func updateTouches(_ touches: Set<UITouch>, with event: UIEvent?) {
        for touch in touches {
            let location = touch.location(in: nil)
            print(String(format: "UIKit(%g,%g) ", round(location.x), round(location.y)), terminator: " ") 
        }
    }
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { 
        updateTouches(touches, with: event) 
    }
    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) { 
        updateTouches(touches, with: event) 
    }
    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { 
        updateTouches(touches, with: event) 
    }
    override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) { 
        updateTouches(touches, with: event) 
    }
}

验证效果

修改后执行测试序列B:

  1. 手指1在红色方块内开始拖拽(触发SwiftUI手势)
  2. 手指2在红色方块外拖拽(触发UIKit触摸)
    → 控制台会同时输出SwiftUI和UIKit的触摸位置日志,两种交互正常响应

内容的提问来源于stack exchange,提问作者Warren Stringer

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 03:35:26