我正在尝试实现一个自定义上下文菜单,该菜单将在用户触摸的位置长按后出现。我一直无法找到一种方法来捕获 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 )
)
}
}
看了这个问题(以及答案中链接的其他问题)后,我尝试了以下操作。
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 中,具体取决于我将它们放置在代码中的位置either触地位置oronLongPressGesture 但不是两者。
我看过但遇到类似问题的其他问题链接如下
如何在 SwiftUI 中检测点击手势位置? https://stackoverflow.com/questions/56513942/how-to-detect-a-tap-gesture-location-in-swiftui
Swift:长按手势识别器 - 检测轻击和长按 https://stackoverflow.com/questions/28058082/swift-long-press-gesture-recognizer-detect-taps-and-long-press这可能是我正在寻找的,但我不确定如何使其适应 SwiftUI。