macOS 14下NSCursor.push()/.set()设置自定义光标被频繁重置问题
macOS 14自定义光标频繁重置问题排查
在macOS 14中出现了macOS 13未存在的异常:原本可以在应用特定视图区域设置自定义鼠标光标,现在光标会频繁重置为标准箭头光标。
用以下代码可复现该问题:鼠标移入红色矩形时光标应变为手型,移出时恢复箭头,但移至矩形右侧时光标会快速重置为箭头,左侧则常保持手型;即使取消注释cursor?.set()行,光标也会在箭头和手型间闪烁。请问这是已知Bug还是我的实现有误?
class ViewController: NSViewController { var cursor: NSCursor? let subframe = CGRect(x: 100, y: 100, width: 300, height: 100) override func loadView() { let subview = NSView(frame: subframe) subview.wantsLayer = true subview.layer!.backgroundColor = NSColor.red.cgColor view = NSView(frame: CGRect(x: 0, y: 0, width: 500, height: 300)) view.addSubview(subview) view.addTrackingArea(NSTrackingArea(rect: .zero, options: [.activeInKeyWindow, .inVisibleRect, .cursorUpdate, .mouseMoved], owner: self)) } override func mouseMoved(with event: NSEvent) { if subframe.contains(view.convert(event.locationInWindow, from: nil)) { if cursor == nil { cursor = .openHand cursor!.push() print("set cursor") } } else if let cursor = cursor { cursor.pop() self.cursor = nil print("unset cursor") } // cursor?.set() } }
问题分析与解决方案
你的实现存在两处核心问题,同时macOS 14的光标管理逻辑也有调整,共同导致了异常:
错误依赖
mouseMoved事件管理光标mouseMoved的触发频率和系统光标更新机制不同步,macOS 14会更主动地校验光标状态,当系统认为光标状态不符合视图层级预期时,会强制重置为默认箭头。正确的做法是重写视图的cursorUpdate(with:)方法,让系统自动处理光标切换。手动管理光标栈易出现状态不一致
用push()和pop()维护光标栈时,若系统在后台自动调整栈状态(比如某些系统事件触发),你的代码维护的cursor变量会和实际栈状态脱节,导致光标闪烁或重置。
修正后的代码
直接在目标子视图中重写光标更新方法,让系统原生处理光标逻辑:
class ViewController: NSViewController { let subframe = CGRect(x: 100, y: 100, width: 300, height: 100) override func loadView() { let subview = CustomCursorView(frame: subframe) subview.wantsLayer = true subview.layer!.backgroundColor = NSColor.red.cgColor view = NSView(frame: CGRect(x: 0, y: 0, width: 500, height: 300)) view.addSubview(subview) } } class CustomCursorView: NSView { override func cursorUpdate(with event: NSEvent) { NSCursor.openHand.set() } }
关于是否是已知Bug
目前苹果开发者社区有不少类似反馈,macOS 14在手动通过光标栈管理自定义光标时,确实存在异常重置的情况。因此优先推荐使用系统原生的视图级光标处理方案,避免手动维护光标栈。
内容的提问来源于stack exchange,提问作者Nickkk
相关产品推荐
相关产品推荐

