主要观点:创建 Mac 应用程序时默认有标准 Mac 菜单栏,commands
修饰符可自定义菜单栏,而从菜单栏向 SwiftUI 视图通信有多种尝试,最终找到使用@FocusedBinding
和focusedSceneValue
的完整解决方案。
关键信息:
- 通过
NotificationCenter
发送消息,需定义通知名、post
通知、添加监听器和处理通知,但会广播到所有视图实例。 - 可使用
appearsActive
环境值判断当前视图是否活跃来改进,但其在窗口合并为标签时存在问题。 - 尝试进入 AppKit 让
NSApp
通过响应链发送选择器但未成功,@FocusedBinding
和focusedValue
在苹果教程示例中有效但对作者数据结构不适用,focusedSceneObject
在带标签窗口中可行但作者已切换到Observation
。 - 最终解决方案使用
@FocusedBinding
和focusedSceneValue
,需定义数据对象、扩展FocusedValues
、设置focusedSceneValue
,在菜单中使用可选链访问数据属性,可添加disabled
修饰符改善用户体验,通过Picker
和本地状态属性处理当前选择显示,代码可在GitHub获取。
重要细节: - 定义通知名的扩展代码
extension Notification.Name { static let menuSelected = Notification.Name("menuSelected") }
。 - 使用
NotificationCenter
发送通知的代码NotificationCenter.default.post(name:.menuSelected, object: nil)
。 - 添加监听器的代码
let menuSelectedNotification = NotificationCenter.default.publisher(for:.menuSelected).receive(on: RunLoop.main)
。 - 在
ContentView
中使用onReceive
处理通知的代码onReceive(menuSelectedNotification) { notification in... }
。 - 在
ContentView
中使用@Environment(\.appearsActive)
判断视图是否活跃的代码@Environment(\.appearsActive) private var appearsActive
。 - 扩展
FocusedValues
的代码extension FocusedValues { @Entry var selectedSymbol: Binding<Symbol>? }
。 - 在
ContentView
中设置focusedSceneValue
的代码focusedSceneValue(\.selectedSymbol, $symbol)
。 - 在
MenuDataApp
中使用@FocusedBinding
的菜单代码@FocusedBinding(\.selectedSymbol) var selectedSymbol
。 - 在
Picker
中处理选择的代码Picker("Symbol", selection: selectedSymbol.name) { ForEach(Symbol.names, id: \.self) { Text(name).tag(name) } }
。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。