SwiftUI Mac如何通过菜单命令创建单实例窗口?
SwiftUI 实现单实例日志窗口(懒加载/启动隐藏)
理想方案:懒加载创建,关闭即销毁,重新打开重建
直接通过条件渲染控制窗口的存在,配合菜单命令触发状态切换,关闭窗口时自动重置状态,实现完全的懒加载和销毁逻辑:
@main struct YourApp: App { // 控制日志窗口的创建/销毁状态 @State private var shouldShowLogWindow = false var body: some Scene { // 主窗口 WindowGroup { MainView() } .commands { CommandGroup(after: .windowArrangement) { Button(shouldShowLogWindow ? "隐藏日志窗口" : "显示日志窗口") { shouldShowLogWindow.toggle() } } } // 条件渲染日志窗口:仅当shouldShowLogWindow为true时才创建 if shouldShowLogWindow { Window("日志", id: "unique-log-window") { LogView() // 你的日志展示视图 .onDisappear { // 窗口关闭时自动重置状态,下次打开会重新创建 shouldShowLogWindow = false } } .windowResizability(.contentSize) // 根据内容调整窗口大小 } } }
逻辑说明
- 启动时
shouldShowLogWindow为false,日志窗口不会被创建,完全懒加载; - 点击菜单命令切换状态为
true,SwiftUI自动创建并显示日志窗口; - 手动关闭窗口时,
onDisappear触发,将shouldShowLogWindow设为false,窗口被销毁; - 再次点击菜单命令,状态变回
true,重新创建新的日志窗口。
退而求其次:启动时隐藏,菜单命令控制显示/隐藏
如果需要窗口始终存在但启动时隐藏,不要用.hidden()修饰符(会永久隐藏),而是通过NSWindow的API手动控制窗口的显示状态:
@main struct YourApp: App { @State private var logWindowVisible = false // 存储日志窗口的引用,用于后续控制显示隐藏 private var logWindow: NSWindow? var body: some Scene { WindowGroup { MainView() } .commands { CommandGroup(after: .windowArrangement) { Button(logWindowVisible ? "隐藏日志窗口" : "显示日志窗口") { guard let window = logWindow else { return } if logWindowVisible { window.orderOut(nil) // 隐藏窗口 } else { window.orderFront(nil) // 显示窗口 NSApp.activate(ignoringOtherApps: true) // 激活应用窗口 } logWindowVisible.toggle() } } } // 启动时创建但隐藏的日志窗口 Window("日志", id: "unique-log-window") { LogView() .onAppear { // 通过窗口ID匹配获取当前日志窗口的引用 logWindow = NSApp.windows.first { $0.identifier == NSUserInterfaceItemIdentifier("unique-log-window") } // 启动时立即隐藏窗口 logWindow?.orderOut(nil) logWindowVisible = false } } .windowResizability(.contentSize) } }
逻辑说明
- 启动时窗口会被创建,但
onAppear中调用orderOut(nil)将其隐藏; - 菜单命令通过操作
NSWindow的orderFront/orderOut方法控制显示/隐藏; - 用窗口ID精准匹配目标窗口,避免误操作其他应用窗口。
内容的提问来源于stack exchange,提问作者Duncan C
相关产品推荐
相关产品推荐

