主要观点:创建 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) `代码` - 列表 > 引用。你还可以使用@来通知其他用户。