You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 23:55:15