Post

Replies

Boosts

Views

Activity

Reply to NavigationLink double click on List for MacOS
Actually, the code pasted in the answer above is now outdated - check the gist instead. The original code had some issues when list was scrolled. Updated gist uses an NSView to detect the clicks instead 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() } } }
Apr ’22
Reply to SwiftUI on macOS: double tap on list item
I made a modifier which seems to do the trick. Uses an NSView to do the actual handling: https://gist.github.com/joelekstrom/91dad79ebdba409556dce663d28e8297 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() } } }
Apr ’22
Reply to NavigationLink double click on List for MacOS
I had the same question and looked around but couldn't find a gesture based solution which works in all cases, especially not with List that has selection states. I made a view modifier using an NSEvent click monitor which seems to solve it as expected for all cases I've tried: extension View { /// Adds a double click handler this view (macOS only) /// /// Example /// ``` /// Text("Hello") /// .onDoubleClick { print("Double click detected") } /// ``` /// - Parameters: /// - inset: To shrink or expand the double click hit area of the view, pass positive or negative values, respectively /// - handler: Block invoked when a double click is detected func onDoubleClick(inset: CGSize = .zero, handler: @escaping () -> Void) -> some View { modifier(DoubleClickHandler(inset: inset, handler: handler)) } } struct DoubleClickHandler: ViewModifier { let inset: CGSize let handler: () -> Void @State private var monitor: Any? ​ private func addListener(frame: NSRect) { let adjustedFrame = frame.insetBy(dx: inset.width, dy: inset.height) monitor = NSEvent.addLocalMonitorForEvents(matching: .leftMouseDown) { if $0.clickCount == 2 { var location = $0.locationInWindow location.y = $0.window!.frame.size.height - location.y // Flip to fix coordinate system mismatch if adjustedFrame.contains(location) { handler() } } return $0 } } private func removeListener() { if let monitor = monitor { NSEvent.removeMonitor(monitor) } } func body(content: Content) -> some View { content.background { GeometryReader { proxy in Color.clear .onAppear { addListener(frame: proxy.frame(in: .global)) } .onDisappear { removeListener() } } } } } https://gist.github.com/joelekstrom/91dad79ebdba409556dce663d28e8297
Apr ’22