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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 22:00:29