在 SwiftUI 中,Commands
修饰符是专门用于 macOS 应用菜单栏定制的核心功能。它允许你创建、修改或替换菜单栏中的命令和菜单项。以下是详细说明:
🚀 核心概念 #
Commands
协议和 .commands
修饰符配合使用,用于定义:
- 应用主菜单栏(文件、编辑、视图等)
- 自定义菜单
- 菜单项及其操作
- 键盘快捷键绑定
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
.commands { // ⬅️ 关键修饰符位置
MyCustomCommands() // 自定义命令组
// 可以添加多个命令组
}
}
}
🛠️ 常用组件 #
1. 创建自定义菜单 #
struct MyCustomCommands: Commands {
var body: some Commands {
CommandMenu("Tools") { // 🛠️ 创建 "Tools" 菜单
Button("Optimize Image") {
// 执行操作
}
.keyboardShortcut("o") // ⌘O 快捷键
Divider() // 菜单分隔线
Toggle("Auto-refresh", isOn: .constant(true))
}
}
}
2. 修改系统菜单 #
CommandGroup(replacing: .newItem) { // 🗑️ 替换"新建"菜单项
Button("New Project...", action: createProject)
.keyboardShortcut("n")
}
CommandGroup(after: .view) { // ➕ 在"视图"菜单后添加
Button("Debug Panel") { showDebug() }
}
3. 键盘快捷键绑定 #
Button("Import Data") {
importData()
}
.keyboardShortcut("i", modifiers: [.command, .shift]) // ⇧⌘I
4. 状态驱动菜单 #
@StateObject private var settings = Settings()
CommandGroup(after: .help) {
Toggle("Dark Mode", isOn: $settings.darkMode)
Picker("Text Size", selection: $settings.textSize) {
Text("Small").tag(0)
Text("Medium").tag(1)
Text("Large").tag(2)
}
}
🔧 特殊功能组件 #
组件 | 用途 |
---|---|
Divider() | 菜单项分隔线 |
Menu("Export") | 嵌套子菜单 |
disabled(true) | 禁用菜单项 |
hidden() | 隐藏菜单项 |
CommandGroupPlacement | 定位系统菜单位置 (.appInfo , .importExport , .undoRedo 等) |
🌰 实用案例 - 文件处理菜单 #
struct FileCommands: Commands {
@Environment(\.openDocument) private var openDocument
var body: some Commands {
CommandGroup(replacing: .newItem) {
Button("New", action: createNewFile)
Button("Open...", action: openFile)
.keyboardShortcut("o")
}
CommandMenu("Export") {
Button("Export as PDF") { exportAsPDF() }
Button("Export as PNG") { exportAsPNG() }
}
}
private func openFile() {
// 通过NSOpenPanel选择文件
}
}
✅ 使用要点 #
- 作用范围:只能在顶级
Scene
(如WindowGroup
) 上使用 - 菜单层次:
- 主菜单 →
CommandMenu
- 菜单项 →
Button
/Toggle
/Picker
/Divider
- 子菜单 →
Menu
- 主菜单 →
- 状态管理:
- 使用
@EnvironmentObject
共享数据 - 通过
@State
管理菜单状态
- 使用
- 平台限制:仅对 macOS 有效,iOS/iPadOS 忽略
⚠️ 常见问题解决方案 #
问题:菜单项无响应?
// ✅ 正确方式 - 将业务逻辑提取到可观察对象
@EnvironmentObject var model: AppModel
Button("Save") {
model.save() // 在ViewModel中实现
}
问题:快捷键冲突?
.keyboardShortcut("s", modifiers: [.command, .option]) // 使用组合修饰键
.keyboardShortcut(.cancelAction) // 使用系统预定义快捷键
💡 高级技巧 #
右键上下文菜单共享命令:
var sharedButton: some View { Button("Shared Action", action: sharedLogic) } // 用于菜单栏 CommandMenu("Tools") { sharedButton } // 用于上下文菜单 .contextMenu { sharedButton }
动态菜单项:
ForEach(recentFiles) { file in Button(file.name) { open(file) } }
多场景不同菜单:
WindowGroup(id: "editor") { ... } .commands { EditorCommands() } Settings { ... } .commands { SettingsCommands() }
SwiftUI 的 Commands 框架提供了声明式的 API 来构建强大的 macOS 菜单系统,实现了菜单逻辑与 UI 组件的无缝集成。