☰
swiftui-expert-skill - macos-scenes
2026/10/9 7:41:07 网站建设 项目流程

macOS 场景参考

适用于 macOS 应用的 SwiftUI 场景类型——Settings、MenuBarExtra、WindowGroup、Window、UtilityWindow和DocumentGroup。涵盖 macOS 专属场景以及带 macOS 特定行为的跨平台场景。

目录

  • 快速查找表
  • Settings(macOS 专属)
  • MenuBarExtra(macOS 专属)
  • WindowGroup(macOS 行为)
  • Window
  • UtilityWindow(macOS 专属)
  • DocumentGroup
  • 平台条件编译
  • 最佳实践

快速查找表

API可用性仅 macOS?macOS 特定行为
WindowGroupmacOS 11.0+否多窗口实例、标签式界面、自动 Window 菜单命令
WindowmacOS 13.0+否唯一窗口关闭时应用退出;将自己添加到 Windows 菜单
UtilityWindowmacOS 15.0+是浮动工具面板;从活动主窗口接收FocusedValues
SettingsmacOS 11.0+是呈现偏好设置窗口(Cmd+,)
MenuBarExtramacOS 13.0+是系统菜单栏中的持久图标/菜单
DocumentGroupmacOS 11.0+否基于文档的菜单栏命令(File > New/Open/Save);多文档窗口

Settings(macOS 专属)

呈现应用的偏好设置窗口,可通过Cmd+,或应用菜单访问。SwiftUI 自动启用 Settings 菜单项并管理窗口生命周期。

Settings{TabView{Tab("General",systemImage:"gear"){GeneralSettingsView()}Tab("Advanced",systemImage:"star"){AdvancedSettingsView()}}.scenePadding().frame(maxWidth:350,minHeight:100)}

多面板偏好设置使用带Tab项的TabView。每个标签页的内容通常是带@AppStorage支持控件的Form。

SettingsLink(macOS 14.0+)

打开 Settings 场景的按钮。用于应用内导航到偏好设置。

structSidebarFooter:View{varbody:someView{SettingsLink{Label("Preferences",systemImage:"gear")}}}

openSettings 环境动作(macOS 14.0+)

以编程方式打开(或前置)Settings 窗口。

structOpenSettingsButton:View{@Environment(\.openSettings)privatevaropenSettingsvarbody:someView{Button("Open Settings"){openSettings()}}}

MenuBarExtra(macOS 专属)

在系统菜单栏中渲染一个持久控件。有两种样式:

  • .menu(默认)——标准下拉菜单
  • .window——带自定义 SwiftUI 视图的弹出面板

菜单样式(下拉)

MenuBarExtra("My Utility",systemImage:"hammer"){Button("Action One"){/* ... */}Button("Action Two"){/* ... */}Divider()Button("Quit"){NSApplication.shared.terminate(nil)}}

窗口样式(弹出面板)

MenuBarExtra("Status",systemImage:"chart.bar"){DashboardView().frame(width:240)}.menuBarExtraStyle(.window)

变体:

  • 可切换——传递isInserted:并带@AppStorage绑定,让用户显示/隐藏该附加项:MenuBarExtra("Status", systemImage: "chart.bar", isInserted: $showMenuBarExtra)
  • 纯菜单栏应用——将MenuBarExtra作为唯一场景 + 在 Info.plist 中设置LSUIElement = true隐藏 Dock 图标。如果用户从菜单栏移除该附加项,应用会自动终止。

WindowGroup(macOS 行为)

在 macOS 上,WindowGroup支持:

  • 多窗口实例——用户可以从 File > New Window 打开多个窗口
  • 标签式界面——用户可以将窗口合并为标签页
  • 自动 Window 菜单——窗口管理命令自动出现
@mainstructMail:App{varbody:someScene{// 基本多窗口支持WindowGroup{MailViewer()}// 以编程方式打开的数据展示窗口WindowGroup("Message",for:Message.ID.self){$messageIDinMessageDetail(messageID:messageID)}}}// 以编程方式打开特定窗口structNewMessageButton:View{varmessage:Message@Environment(\.openWindow)privatevaropenWindowvarbody:someView{Button("Open Message"){openWindow(value:message.id)}}}

与Window的关键区别:WindowGroup即使所有窗口都关闭也会保持应用运行。Window(作为唯一场景)在关闭时会退出应用。


Window

单个、唯一的窗口场景。系统确保只存在一个实例。

@mainstructMail:App{varbody:someScene{WindowGroup{MailViewer()}// 补充性的单例窗口Window("Connection Doctor",id:"connection-doctor"){ConnectionDoctor()}}}// 以编程方式打开——如果已打开则前置structOpenDoctorButton:View{@Environment(\.openWindow)privatevaropenWindowvarbody:someView{Button("Connection Doctor"){openWindow(id:"connection-doctor")}}}

作为唯一场景的 Window

如果Window是唯一场景,窗口关闭时应用退出:

@mainstructVideoCall:App{varbody:someScene{Window("VideoCall",id:"main"){CameraView()}}}

建议:在大多数情况下,主场景优先使用WindowGroup。对补充性的单例窗口使用Window。


UtilityWindow(macOS 专属)

用于工具面板和检查器面板的专用浮动窗口。自 macOS 15.0 起可用。

关键行为:

  • 从聚焦的主场景接收FocusedValues(像菜单栏命令一样)
  • 浮动在主窗口之上(默认层级:.floating)
  • 应用不再活跃时隐藏
  • 仅在明确需要时才获得焦点(例如点击标题栏)
  • 可用 Escape 键关闭
  • 默认不可最小化
  • 自动向 View 菜单添加显示/隐藏项
@mainstructPhotoBrowser:App{varbody:someScene{WindowGroup{PhotoGallery()}UtilityWindow("Photo Info",id:"photo-info"){PhotoInfoViewer()}}}structPhotoInfoViewer:View{// 根据哪个主窗口被聚焦自动更新@FocusedValue(PhotoSelection.self)privatevarselectedPhotosvarbody:someView{ifletphotos=selectedPhotos{Text("\(photos.count)photos selected")}else{Text("No selection").foregroundStyle(.secondary)}}}

提示:使用.commandsRemoved()移除自动的 View 菜单项,并在命令中的其他位置放置WindowVisibilityToggle。


DocumentGroup

带自动文件管理的文档型应用。在 macOS 上提供:

  • 基于文档的菜单栏命令(File > New、Open、Save、Revert)
  • 同时多个文档窗口
  • 在 iOS 上,显示文档浏览器
DocumentGroup(newDocument:TextFile()){configinContentView(document:config.$document)}

文档类型必须遵循FileDocument(值类型)或ReferenceFileDocument(引用类型)。关键要求:

structTextFile:FileDocument{staticvarreadableContentTypes:[UTType]{[.plainText]}vartext:String=""init(){}init(configuration:ReadConfiguration)throws{text=String(data:configuration.file.regularFileContents??Data(),encoding:.utf8)??""}funcfileWrapper(configuration:WriteConfiguration)throws->FileWrapper{FileWrapper(regularFileWithContents:Data(text.utf8))}}

对于多种文档类型,添加额外的DocumentGroup场景——对只读格式使用DocumentGroup(viewing:)。


平台条件编译

始终将 macOS 专属场景包裹在#if os(macOS)中:

@mainstructMyApp:App{varbody:someScene{WindowGroup{ContentView()}#ifos(macOS)Settings{SettingsView()}MenuBarExtra("Status",systemImage:"bolt"){StatusMenu()}#endif}}

最佳实践

  • 偏好设置使用Settings——优先于自定义偏好设置窗口
  • 菜单栏项使用MenuBarExtra——优先于直接管理 AppKit 的NSStatusItem
  • 主场景使用WindowGroup——将Window保留给补充性单例
  • 检查器/面板使用UtilityWindow——它自动处理浮动、焦点和可见性
  • 文档型应用使用DocumentGroup——它提供完整的 File 菜单和文档生命周期
  • 用#if os(macOS)门控 macOS 专属场景,用于多平台项目
  • 使用openWindow(id:)以编程方式打开窗口——它会把已有窗口前置

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询