繁体   English   中英

在 swiftUI 中捕获 onLongPressGesture 的 touchDown 位置?

[英]Capture touchDown location of onLongPressGesture in swiftUI?

我正在尝试实现一个自定义上下文菜单,该菜单将在用户触摸的位置长按后出现。 我一直无法找到一种方法来捕获 onLongPressGesture 的触地事件的 XY 位置。

这是我开始的地方

struct ExampleView: View {
    @State var showCustomContextMenu = false
    @State var longPressLocation = CGPoint.zero
    
    var body: some View {
        Rectangle()
            .foregroundColor(Color.green)
            .frame(width: 100.0, height: 100.0)
            .onLongPressGesture {
                print("OnLongPressGesture")
                self.showCustomContextMenu = true
            }
            .overlay(
                Rectangle()
                    .foregroundColor(Color.red)
                    .frame(width: 50.0, height: 50.0)
                    .position(longPressLocation) // <----- this is what I need to capture.
                    .opacity( (showCustomContextMenu) ? 1 : 0 )
        )
    }
}

在查看了这个问题(以及答案中链接的其他 SO 问题)之后,我尝试了以下操作。

如何检测没有移动或持续时间的 SwiftUI touchDown 事件?

struct ExampleView: View {
    @State var showCustomContextMenu = false
    @State var longPressLocation = CGPoint.zero
    
    var body: some View {
        ZStack{
            Rectangle()
                .foregroundColor(Color.green)
                .frame(width: 100.0, height: 100.0)
                .onLongPressGesture {
                    print("OnLongPressGesture")
                    self.showCustomContextMenu = true
                }
                .overlay(
                    Rectangle()
                        .foregroundColor(Color.red)
                        .frame(width: 50.0, height: 50.0)
                        .position(longPressLocation)
                        .opacity( (showCustomContextMenu) ? 1 : 0 )
            )
            TapView { point in
                self.longPressLocation = point
                print("Point: \(point)")
            }.background(Color.gray).opacity(0.5)
        }
    }
}

struct TapView: UIViewRepresentable {
    var tappedCallback: ((CGPoint) -> Void)

    func makeUIView(context: UIViewRepresentableContext<TapView>) -> TapView.UIViewType {
        let v = UIView(frame: .zero)
        let gesture = SingleTouchDownGestureRecognizer(target: context.coordinator,
                                                       action: #selector(Coordinator.tapped))
        v.addGestureRecognizer(gesture)
        return v
    }

    class Coordinator: NSObject {
        var tappedCallback: ((CGPoint) -> Void)

        init(tappedCallback: @escaping ((CGPoint) -> Void)) {
            self.tappedCallback = tappedCallback
        }

        @objc func tapped(gesture:UITapGestureRecognizer) {
            self.tappedCallback(gesture.location(in: gesture.view))
        }
    }

    func makeCoordinator() -> TapView.Coordinator {
        return Coordinator(tappedCallback:self.tappedCallback)
    }

    func updateUIView(_ uiView: UIView,
                      context: UIViewRepresentableContext<TapView>) {
    }
}

class SingleTouchDownGestureRecognizer: UIGestureRecognizer {
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
        if self.state == .possible {
            self.state = .recognized
        }
    }
    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent) {
        self.state = .failed
    }
    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent) {
        self.state = .failed
    }
}

这几乎可行,但是,这给我留下的问题是,由于 Rectangle() 和 TapView() 位于 ZStack 中,这取决于我将它们放置在代码中的位置,因此我可以得到touchDown位置onLongPressGesture,但不能同时获得两者。

我看过但遇到类似问题的其他 SO 问题链接如下

如何检测 SwiftUI 中的点击手势位置?

Swift:长按手势识别器 - 检测轻按和长按这可能是我正在寻找的,但我不确定如何使其适应 SwiftUI。

这是一个可能的方法的演示。 它需要两个手势的组合:长按检测长按和拖动检测位置。

使用 Xcode 12 / iOS 14 进行测试。(在以下系统中,可能需要将self.添加到某些属性使用中)

演示

struct ExampleView: View {
    @State var showCustomContextMenu = false
    @State var longPressLocation = CGPoint.zero

    var body: some View {
        Rectangle()
            .foregroundColor(Color.green)
            .frame(width: 100.0, height: 100.0)
            .onTapGesture { showCustomContextMenu = false } // just for demo
            .gesture(LongPressGesture(minimumDuration: 1).sequenced(before: DragGesture(minimumDistance: 0, coordinateSpace: .local))
                .onEnded { value in
                    switch value {
                        case .second(true, let drag):
                            longPressLocation = drag?.location ?? .zero   // capture location !!
                            showCustomContextMenu = true
                        default:
                            break
                    }
            })
            .overlay(
                Rectangle()
                    .foregroundColor(Color.red)
                    .frame(width: 50.0, height: 50.0)
                    .position(longPressLocation)
                    .opacity( (showCustomContextMenu) ? 1 : 0 )
                    .allowsHitTesting(false)
        )
    }
}

备份

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM