You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI中MenuBarExtra应用如何设置Settings视图窗口层级?

解决SwiftUI MenuBarExtra中设置窗口后置及关闭后菜单消失的问题

问题分析

  1. 设置窗口后置:使用NSApp.sendAction(Selector(("showSettingsWindow:")))唤起设置窗口时,未明确指定窗口层级和前置状态,导致窗口被其他应用遮挡。
  2. 关闭设置窗口后MenuBarExtra消失:全局设置所有窗口为.floating后,关闭设置窗口时应用失去所有活跃窗口,系统将应用转入后台并隐藏MenuBarExtra,但进程仍保持运行。

解决方案

1. 规范唤起设置窗口的方式

使用SwiftUI官方提供的OpenSettingsAction(macOS 13+ / iOS 16+)替代旧的Selector调用,更安全且符合框架规范。

2. 单独设置设置窗口的层级

仅针对设置窗口设置.floating层级并强制前置,避免影响其他窗口的行为。

3. 确保应用无窗口时MenuBarExtra仍可见

设置应用的激活策略为.accessory,保证即使没有任何窗口,MenuBarExtra仍会保留在菜单栏中。

完整代码示例

import SwiftUI

struct MainScene: Scene {
    var body: some Scene {
        WindowGroup(id: "mainscene") {
            Button("close") {
                NSApplication.shared.keyWindow?.close()
            }
            .task {
                NSApp.windows.first?.close()
            }
        }
    }
}

struct SettingView: View {
    var body: some View {
        Text("偏好设置页面")
            .frame(width: 300, height: 200)
            .onAppear {
                // 定位到设置窗口并调整层级
                if let settingsWindow = NSApp.windows.first(where: {
                    $0.className == "NSWindow" && $0.title.contains("Settings")
                }) {
                    settingsWindow.level = .floating
                    settingsWindow.makeKeyAndOrderFront(nil)
                    NSApp.activate(ignoringOtherApps: true)
                }
            }
    }
}

struct Demo: App {
    init() {
        // 设置应用激活策略,确保无窗口时MenuBarExtra仍显示
        NSApp.setActivationPolicy(.accessory)
    }
    
    var body: some Scene {
        MainScene()
        Settings {
            SettingView()
        }
        MenuBarExtra("Menu Bar", systemImage: "swift") {
            Button("偏好设置...") {
                // 使用官方API唤起设置窗口
                openSettings()
            }
            Divider()
            Button("退出") {
                NSApplication.shared.terminate(nil)
            }.keyboardShortcut("q")
        }
        // 注入openSettings环境动作(macOS13+自动支持,此处显式声明兼容)
        .environment(\.openSettings, OpenSettingsAction {
            NSApp.sendAction(Selector(("showSettingsWindow:")), to: nil, from: nil)
        })
    }
}

额外说明

  • 如果你的项目需要兼容macOS 12及以下版本,可以保留NSApp.sendAction(Selector(("showSettingsWindow:")))的调用方式,但需要在设置窗口出现后手动调整层级和前置状态。
  • .accessory激活策略会让应用不在Dock中显示,若需要Dock图标,可改用.regular策略,并确保至少有一个窗口始终存在(比如隐藏的主窗口)。

内容的提问来源于stack exchange,提问作者FaiChou

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 11:10:35