Mac 菜单栏与 SwiftUI - TrozWare

主要观点:创建 Mac 应用程序时默认有标准 Mac 菜单栏,commands修饰符可自定义菜单栏,而从菜单栏向 SwiftUI 视图通信有多种尝试,最终找到使用@FocusedBindingfocusedSceneValue的完整解决方案。
关键信息:

  • 通过NotificationCenter发送消息,需定义通知名、post通知、添加监听器和处理通知,但会广播到所有视图实例。
  • 可使用appearsActive环境值判断当前视图是否活跃来改进,但其在窗口合并为标签时存在问题。
  • 尝试进入 AppKit 让NSApp通过响应链发送选择器但未成功,@FocusedBindingfocusedValue在苹果教程示例中有效但对作者数据结构不适用,focusedSceneObject在带标签窗口中可行但作者已切换到Observation
  • 最终解决方案使用@FocusedBindingfocusedSceneValue,需定义数据对象、扩展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) } }
阅读 10
0 条评论