如何在macOS应用区域永久将NSCursor设置为pointingHand?
问题:SwiftUI应用全局设置NSCursor为pointingHand,避免使用onHover修饰符
我希望整个应用内的NSCursor都变为pointingHand。最初尝试通过按钮操作修改NSCursor,虽生效但鼠标移动后恢复为macOS默认样式。之后使用了如下代码:
struct ContentView: View { var body: some View { ZStack { Color.blue Text("Hello, world!") } .onHover(perform: { value in NSCursor.pointingHand.push() }) } }
但我不喜欢这段代码,因为onHover会几乎每秒更新NSCursor,像是在和macOS竞争将其改为pointingHand,这种实现甚至可用定时器替代,因此确定onHover并非最优方案。请问无需onHover修饰符,如何仅在应用区域修改NSCursor形状?
解决方案
方法1:通过NSViewRepresentable封装光标设置
自定义一个CursorView,利用AppKit的NSView添加光标区域,只会在视图加载时设置一次,不会频繁触发更新:
struct CursorView: NSViewRepresentable { let cursor: NSCursor func makeNSView(context: Context) -> NSView { let view = NSView() view.addCursorRect(view.bounds, cursor: cursor) return view } func updateNSView(_ nsView: NSView, context: Context) { // 更新时移除旧光标区域,添加新的 nsView.removeCursorRect(nsView.bounds, cursor: context.coordinator.previousCursor) nsView.addCursorRect(nsView.bounds, cursor: cursor) context.coordinator.previousCursor = cursor } func makeCoordinator() -> Coordinator { Coordinator() } class Coordinator { var previousCursor: NSCursor = .arrow } } // 使用示例 struct ContentView: View { var body: some View { ZStack { Color.blue Text("Hello, world!") // 添加光标视图,禁用点击测试避免影响其他交互 CursorView(cursor: .pointingHand) .allowsHitTesting(false) } } }
方法2:在App层面为窗口设置全局光标
直接获取应用窗口,为内容视图添加光标区域,覆盖整个应用界面:
@main struct CursorDemoApp: App { var body: some Scene { WindowGroup { ContentView() .onAppear { guard let window = NSApplication.shared.windows.first else { return } guard let contentView = window.contentView else { return } contentView.addCursorRect(contentView.bounds, cursor: .pointingHand) } } } }
方法3:封装ViewModifier实现复用
把光标逻辑封装成ViewModifier,方便在任意视图上快速应用:
struct GlobalCursorModifier: ViewModifier { let cursor: NSCursor func body(content: Content) -> some View { content .background { CursorView(cursor: cursor) .allowsHitTesting(false) } } } // 扩展View简化调用 extension View { func setGlobalCursor(_ cursor: NSCursor) -> some View { modifier(GlobalCursorModifier(cursor: cursor)) } } // 使用示例 struct ContentView: View { var body: some View { ZStack { Color.blue Text("Hello, world!") } .setGlobalCursor(.pointingHand) } }
以上方法都通过AppKit的addCursorRectAPI设置光标区域,macOS会自动管理光标样式,不需要持续调用push(),彻底避免了和系统竞争光标的问题。
内容的提问来源于stack exchange,提问作者swiftPunk
相关产品推荐
相关产品推荐

