SwiftUI中处理标尺双击事件遇编译错误,求解决方案
问题解决:SwiftUI标尺滚动视图双击弹窗的编译错误与实现方案
编译错误原因
你遇到的'override' can only be specified on class members错误,是因为RulerScrollView是**结构体(struct)**而非类(class),结构体不允许使用override关键字重写方法——而且mouseDown(with:)也不属于NSViewRepresentable协议的方法,直接在结构体中添加这个方法本身就是错误的。
正确实现步骤
1. 自定义NSScrollView子类处理标尺双击
创建一个NSScrollView的子类,专门处理标尺区域的双击事件:
class CustomRulerScrollView: NSScrollView { // 定义双击回调闭包 var onRulerDoubleClick: (() -> Void)? override func mouseDown(with event: NSEvent) { super.mouseDown(with: event) // 仅当双击标尺区域时触发回调 let hitView = hitTest(event.locationInWindow) if event.clickCount == 2, hitView is NSRulerView { onRulerDoubleClick?() } } }
这里通过hitTest判断点击的是标尺视图(NSRulerView),避免双击滚动视图其他区域误触发弹窗。
2. 修改NSViewRepresentable结构体
更新RulerScrollView,使用自定义的滚动视图类,并添加回调闭包传递双击事件:
struct RulerScrollView<Content: View>: NSViewRepresentable { @ObservedObject var dm: DrawModel let content: Content let onRulerDoubleClick: () -> Void init(_ dm: DrawModel, @ViewBuilder content: () -> Content, onRulerDoubleClick: @escaping () -> Void) { self.dm = dm self.content = content() self.onRulerDoubleClick = onRulerDoubleClick } func makeNSView(context: Context) -> CustomRulerScrollView { let scrollView = CustomRulerScrollView() scrollView.hasVerticalRuler = true scrollView.hasHorizontalRuler = true scrollView.rulersVisible = dm.showRulers // 绑定双击回调 scrollView.onRulerDoubleClick = onRulerDoubleClick let hostingView = NSHostingView(rootView: content) hostingView.wantsLayer = true hostingView.layer?.backgroundColor = NSColor.white.cgColor scrollView.documentView = hostingView return scrollView } func updateNSView(_ nsView: CustomRulerScrollView, context: Context) { nsView.rulersVisible = dm.showRulers } }
3. 调用时绑定弹窗触发逻辑
直接在调用RulerScrollView时传递弹窗显示的动作,无需使用通知中心:
Stack { RulerScrollView(dm, onRulerDoubleClick: { isShowingRulerSettings = true }) { DrawingView(dm) } .background(Color.white) } .alert(isPresented: $isShowingRulerSettings) { Alert(title: Text("Ruler Settings"), message: Text("Settings here"), primaryButton: .default(Text("OK")), secondaryButton: .cancel()) }
额外说明
如果坚持使用通知中心的方式,只需把CustomRulerScrollView中的闭包调用替换为通知发送即可:
// 在CustomRulerScrollView的mouseDown中替换 if event.clickCount == 2, hitView is NSRulerView { NotificationCenter.default.post(name: Notification.Name("ShowRulerSettings"), object: nil) }
然后在调用代码中保留onReceive监听通知的逻辑即可。
内容的提问来源于stack exchange,提问作者Keith
相关产品推荐
相关产品推荐

