macOS 上的 SwiftUI - 同时处理单击和双击



考虑 SwiftUI 中的这个视图:

struct MyView: View {
var body: some View {
Rectangle()
.fill(Color.blue)
.frame(width: 200, height: 200)
.onTapGesture {
print("single clicked")
}
}
}

现在我们正在处理单击。假设您也想处理双击,但使用单独的回调。

您有 2 个选项:

  • 单击后添加双击处理程序 -这根本不起作用
  • 在单击处理程序之前添加双击处理程序,这有点工作:
struct MyView: View {
var body: some View {
Rectangle()
.fill(Color.blue)
.frame(width: 200, height: 200)
.onTapGesture(count: 2) {
print("double clicked")
}
.onTapGesture {
print("single clicked")
}
}
}

双击处理程序被正确调用,但单击处理程序在大约 250 毫秒的延迟后调用。

任何想法如何解决这个问题?

这是可能的方法(使用 Xcode 11.2/macOS 10.15 测试(

struct MyView: View {
var body: some View {
Rectangle()
.fill(Color.blue)
.frame(width: 200, height: 200)
.gesture(TapGesture(count: 2).onEnded {
print("double clicked")
})
.simultaneousGesture(TapGesture().onEnded {
print("single clicked")
})
}
}

在列表中启用selection时,基于手势的解决方案无法正常工作,因为第一次点击会延迟实际选择。我制作了一个双击修饰符,它适用于任何视图,并且似乎在所有情况下都能以我期望的方式解决它:

extension View {
/// Adds a double click handler this view (macOS only)
///
/// Example
/// ```
/// Text("Hello")
///     .onDoubleClick { print("Double click detected") }
/// ```
/// - Parameters:
///   - handler: Block invoked when a double click is detected
func onDoubleClick(handler: @escaping () -> Void) -> some View {
modifier(DoubleClickHandler(handler: handler))
}
}
struct DoubleClickHandler: ViewModifier {
let handler: () -> Void
func body(content: Content) -> some View {
content.overlay {
DoubleClickListeningViewRepresentable(handler: handler)
}
}
}
struct DoubleClickListeningViewRepresentable: NSViewRepresentable {
let handler: () -> Void
func makeNSView(context: Context) -> DoubleClickListeningView {
DoubleClickListeningView(handler: handler)
}
func updateNSView(_ nsView: DoubleClickListeningView, context: Context) {}
}
class DoubleClickListeningView: NSView {
let handler: () -> Void
init(handler: @escaping () -> Void) {
self.handler = handler
super.init(frame: .zero)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func mouseDown(with event: NSEvent) {
super.mouseDown(with: event)
if event.clickCount == 2 {
handler()
}
}
}

https://gist.github.com/joelekstrom/91dad79ebdba409556dce663d28e8297

最新更新