Mac OS菜单栏图标右键点击触发弹出功能菜单的实现问题
解决方案
你现在的核心问题是NSStatusBarButton扩展内的右键事件无法直接访问AppDelegate中的弹窗实例,也没有对应的逻辑触发选项弹窗,按以下步骤修改即可:
核心修改点
- 给选项弹窗
popOverOptions补充基础行为配置,保证和主弹窗行为一致 - 给
AppDelegate新增右键点击的处理方法,专门触发选项弹窗 - 在右键事件回调中关联
AppDelegate的右键处理方法 - 弹窗触发逻辑中增加互斥判断,保证同一时间只有一个弹窗打开
修改后完整代码
@main struct MenuNoteApp: App { let persistenceController = PersistenceController.shared @Environment(\.scenePhase) var scenePhase @NSApplicationDelegateAdaptor(AppDelegate.self) var delegate var body: some Scene { WindowGroup { ContentView().environment(\.managedObjectContext, PersistenceController.preview.container.viewContext) } .onChange(of: scenePhase) { _ in persistenceController.save() } } } extension NSStatusBarButton { open override func rightMouseUp(with event: NSEvent) { super.rightMouseUp(with: event) // 关联AppDelegate的右键处理逻辑 guard let delegate = NSApplication.shared.delegate as? AppDelegate else { return } delegate.rightMenuButtonToggle(sender: self) } } class AppDelegate: NSObject,NSApplicationDelegate{ let persistenceController = PersistenceController.shared // Status Item var statusItem: NSStatusItem? // PopOver var popOver = NSPopover() var popOverOptions = NSPopover() func applicationDidFinishLaunching( _ notification: Notification){ // Menu View let menuView = MenuView().environment(\.managedObjectContext, PersistenceController.preview.container.viewContext) // 主弹窗配置 popOver.behavior = .transient popOver.animates = true popOver.contentViewController = NSViewController() popOver.contentViewController?.view = NSHostingView(rootView: menuView) // 选项弹窗补充配置 popOverOptions.behavior = .transient popOverOptions.animates = true popOverOptions.contentViewController = NSViewController() popOverOptions.contentViewController?.view = NSHostingView(rootView: OptionsView()) // 创建状态栏按钮 statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength) if let MenuButton = statusItem?.button { MenuButton.image = NSImage(systemSymbolName: "note", accessibilityDescription: nil) MenuButton.action = #selector(MenuButtonToggle) } } // 左键点击处理 @objc func MenuButtonToggle(sender: AnyObject){ // 先关闭已打开的选项弹窗 if popOverOptions.isShown{ popOverOptions.performClose(sender) } if popOver.isShown{ popOver.performClose(sender) } else { if let menuButton = statusItem?.button{ self.popOver.show(relativeTo: menuButton.bounds, of: menuButton, preferredEdge: NSRectEdge.minY) } } } // 右键点击处理 @objc func rightMenuButtonToggle(sender: AnyObject){ // 先关闭已打开的主弹窗 if popOver.isShown{ popOver.performClose(sender) } if popOverOptions.isShown{ popOverOptions.performClose(sender) } else { if let menuButton = statusItem?.button{ self.popOverOptions.show(relativeTo: menuButton.bounds, of: menuButton, preferredEdge: NSRectEdge.minY) } } } }
退出功能补充
如果需要在OptionsView中加退出按钮,直接在视图内添加以下代码即可:
Button("退出应用") { NSApplication.shared.terminate(nil) }
内容的提问来源于stack exchange,提问作者marcus
相关产品推荐
相关产品推荐

