尽管我喜欢(并点赞)被接受的答案,但我找到了一种方法,使视图能够响应右键单击事件,而无需符合
NSViewRepresentable
。这种方法更加清晰地集成到我的应用程序中,因此对于其他面临此问题的人来说,可能值得考虑作为一种可能性。
我的解决方案首先需要愿意接受传统上在 macOS 中将右键单击和控制-左键单击视为等效的约定。此解决方案不允许从控制-右键单击中区分处理控制-左键单击。但是,由于它仅添加
.control
并将其转换为左键单击,因此可以处理任何其他修饰符。
如果您使用 SwiftUI 上下文菜单,则此方法可能会破坏它们。我没有测试过。
所以,将右键单击事件转换为带有控制键修饰符的左键单击事件。
为了实现这一点,我子类化了
NSHostingView
,并提供了一个方便的
NSEvent
扩展。
fileprivate extension NSEvent
{
var translateRightMouseButtonEvent: NSEvent
{
guard let cgEvent = self.cgEvent else { return self }
switch type
{
case .rightMouseDown: cgEvent.type = .leftMouseDown
case .rightMouseUp: cgEvent.type = .leftMouseUp
case .rightMouseDragged: cgEvent.type = .leftMouseDragged
default: return self
}
cgEvent.flags.formUnion(.maskControl)
guard let nsEvent = NSEvent(cgEvent: cgEvent) else { return self }
return nsEvent
}
}
class MyHostingView<Content: View>: NSHostingView<Content>
{
@objc public override func rightMouseDown(with event: NSEvent) {
super.mouseDown(with: event.translateRightMouseButtonEvent)
}
@objc public override func rightMouseUp(with event: NSEvent) {
super.mouseUp(with: event.translateRightMouseButtonEvent)
}
@objc public override func rightMouseDragged(with event: NSEvent) {
super.mouseDragged(with: event.translateRightMouseButtonEvent)
}
}
然后在 AppDelegate.didFinishLaunching
中我进行了更改。
window.contentView = NSHostingView(rootView: contentView)
to
window.contentView = MyHostingView(rootView: contentView)
当然,任何其他可能涉及到NSHostingView
的代码都需要进行类似的更改。通常在AppDelegate
中的引用是唯一的,但在重要项目中可能会有其他引用。
然后,在SwiftUI代码中,右键单击事件将显示为带有.control
修饰符的TapGesture
。
Text("Right-clickable Text")
.gesture(
TapGesture().modifiers(.control)
.onEnded
{ _ in
print("Control-Clicked")
}
)
.onTapGesture()
看看吧。 - ABC.gesture(TapGesture().onEnded(.......))
的行为完全相同。 - Ky -