SwiftUI中实现多指同时长按检测的技术问询
多指长按检测与多圆圈绘制实现方案
要实现多指同时长按检测并在对应位置绘制圆圈,我们可以通过DragGesture跟踪所有触摸点,结合触摸起始时间判断是否达到长按条件,同时维护每个触摸的独立状态。以下是完整的实现代码:
import SwiftUI // 存储单根手指的触摸信息 struct TouchInfo: Identifiable { let id: UUID var location: CGPoint let startTime: Date var didTriggerLongPress: Bool = false } // 存储需要显示的圆圈数据 struct CircleMarker: Identifiable { let id: UUID let location: CGPoint let color: Color } struct ContentView: View { // 记录所有当前触摸的信息 @State private var activeTouches: [TouchInfo] = [] // 记录已触发长按的圆圈 @State private var longPressCircles: [CircleMarker] = [] // 长按所需的最短时长(秒) private let longPressDuration: TimeInterval = 1 var multiFingerLongPressGesture: some Gesture { DragGesture(minimumDistance: 0, coordinateSpace: .local) .onChanged { value in // 更新当前触摸的位置,或添加新触摸 let touchId = value.id if let index = activeTouches.firstIndex(where: { $0.id == touchId }) { activeTouches[index].location = value.location // 检查是否达到长按时长且未触发过 let elapsedTime = Date().timeIntervalSince(activeTouches[index].startTime) if elapsedTime >= longPressDuration && !activeTouches[index].didTriggerLongPress { activeTouches[index].didTriggerLongPress = true // 添加新的圆圈标记 longPressCircles.append(CircleMarker( id: touchId, location: value.location, color: Color.random() )) } } else { // 新手指触摸,记录起始时间和位置 activeTouches.append(TouchInfo( id: touchId, location: value.location, startTime: Date() )) } } .onEnded { value in // 手指抬起时,移除对应触摸信息和圆圈 activeTouches.removeAll(where: { $0.id == value.id }) longPressCircles.removeAll(where: { $0.id == value.id }) } } var body: some View { ZStack { Rectangle() .foregroundColor(Color(.background)) .ignoresSafeArea() .gesture(multiFingerLongPressGesture) // 绘制所有已触发的长按圆圈 ForEach(longPressCircles) { circle in Circle() .foregroundColor(circle.color) .frame(width: 100, height: 100) .position(circle.location) .allowsHitTesting(false) } VStack(spacing: 8) { Image(systemName: "hands.sparkles") .imageScale(.large) .foregroundStyle(.tint) .font(.largeTitle) Text("长按任意数量手指查看圆圈") } .padding() } } } // 扩展Color,生成随机颜色 extension Color { static func random() -> Color { Color( red: Double.random(in: 0...1), green: Double.random(in: 0...1), blue: Double.random(in: 0...1) ) } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }
核心逻辑说明
- 触摸状态跟踪:通过
TouchInfo结构体记录每根手指的唯一ID、位置、起始时间和长按触发状态,确保多手指操作互不干扰。 - 长按判断:在
DragGesture的onChanged回调中,计算触摸持续时长,当达到设定的longPressDuration且未触发过长按时,生成对应位置的圆圈。 - 多圆圈绘制:使用
ForEach遍历longPressCircles数组,动态渲染每个触发长按的手指位置的圆圈,手指抬起时自动移除对应圆圈。 - 无距离限制的拖拽手势:设置
minimumDistance: 0,让手势能够捕获手指静止时的触摸状态,完美适配长按场景。
内容的提问来源于stack exchange,提问作者Peter
相关产品推荐
相关产品推荐

