如何在SwiftUI中通过代码控制macOS MenuBarExtra的显示与隐藏?
原生SwiftUI的限制
截至SwiftUI 5(对应macOS 14+),原生框架并未提供直接API控制MenuBarExtra的展开/收起状态——MenuBarExtra的显示逻辑由系统接管,没有暴露可调用的控制接口,因此必须借助AppKit的底层API实现需求。
基于AppKit的实现方案
MenuBarExtra底层基于NSStatusItem(菜单样式)或NSWindow(窗口样式)实现,我们可以通过AppKit API找到对应实例并触发展开。
1. 针对菜单样式的MenuBarExtra(你的代码使用的类型)
你的MenuBarExtra是默认的菜单样式,可通过找到对应的NSStatusItem并模拟点击来展开菜单:
获取目标NSStatusItem
遍历系统状态栏项目,通过标题或图标匹配你的MenuBarExtra:
private func targetStatusItem() -> NSStatusItem? { for item in NSApplication.shared.statusItems { // 匹配你定义MenuBarExtra时的标题"Title" if item.button?.title == "Title" { return item } // 若标题可能动态变化,可改用图标名称匹配 // if item.button?.image?.rawValue == "sample_icon" { // return item // } } return nil }
触发菜单展开
调用NSStatusItem按钮的performClick方法,模拟用户点击:
func openMenuBarExtra() { guard let statusItem = targetStatusItem() else { return } statusItem.button?.performClick(nil) }
将openMenuBarExtra()绑定到你的全局快捷键处理逻辑中即可。
2. 针对窗口样式的MenuBarExtra(若后续切换为该类型)
如果你的MenuBarExtra使用.window修饰符(如MenuBarExtra("Title", style: .window) { ... }),则需要找到对应的NSWindow并调用显示方法:
func openWindowStyleMenuBarExtra() { for window in NSApplication.shared.windows { // 匹配窗口标题 if window.title == "Title" { window.makeKeyAndOrderFront(nil) } } }
注意事项
- 若存在多个状态栏项目,建议结合标题和图标做双重校验,确保匹配逻辑唯一,避免误操作其他应用的状态栏项。
- 该方案使用的都是AppKit公开API,不存在审核风险。
内容的提问来源于stack exchange,提问作者cyril
相关产品推荐
相关产品推荐

