我正在尝试更改 macOS SwiftUI 应用程序中的默认命令。我想将一些自定义命令附加到“查看”菜单,但我无法让它工作。
这是我尝试过的:
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
AppView()
.environmentObject(AppModel.shared)
.environment(\.managedObjectContext, AppModel.shared.cloudKitCoordinator.coreDataStack.viewContext)
}
.commands {
ViewCommands()
SidebarCommands()
ElementCommands()
NavigationCommands()
}
}
}
struct ViewCommands: Commands {
var body: some Commands {
CommandMenu("View") {
Button("Do something View related") {}
}
}
}
但它不是将命令附加到“查看”菜单,而是创建第二个同名菜单:
有没有人有幸更改了默认命令菜单,或者这只是 SwiftUI 的一部分,仍然有点原始?
使用 CommandGroup,它具有用于追加或替换现有菜单的初始化选项:
.commands {
CommandGroup(before: CommandGroupPlacement.newItem) {
Button("before item") {
print("before item")
}
}
CommandGroup(replacing: CommandGroupPlacement.appInfo) {
Button("Custom app info") {
// show custom app info
}
}
CommandGroup(after: CommandGroupPlacement.newItem) {
Button("after item") {
print("after item")
}
}
}
很好的教程:https://swiftwithmajid.com/2020/11/24/commands-in-swiftui/
接受的答案在建议
CommandGroup
而不是 CommandMenu
方面总体上是正确的,并且有助于向我们指出 Swift with Majid (一个很棒的网站),但令人愤怒的是没有给我们确切的答案 - 哪个 CommandGroupPlacement
用于 View 菜单?
为了避免所有其他人的尝试和错误,它是
CommandGroup(before: CommandGroupPlacement.toolbar) {
Toggle("Show X", isOn: $model.settings.showX)
Toggle("Show Y", isOn: $model.settings.showY)
Divider()
}
extension AppDelegate {
func applicationWillUpdate(_ notification: Notification) {
DispatchQueue.main.async {
guard let currentMainMenu = NSApplication.shared.mainMenu else { return }
// remove some items that cannot be deleted from SwiftUI
["Edit", "File", "Window"].forEach { name in
currentMainMenu.item(withTitle: name).map { NSApp.mainMenu?.removeItem($0) }
}
guard let menu = currentMainMenu.item(withTitle: "View")?.submenu else { return }
// remove sub-items of "View"
menu.removeAllItems()
//add new items
menu.addItem(self.recentsPlusFavorites)
menu.addItem(self.recentsMini)
menu.addItem(self.recentsLarger)
}
}
}
从 iOS 16.0、macOS 13.0 开始,Apple 引入了新的 API 来处理该问题。来自 SwiftUI 文档,代码示例:
/// @main
/// struct Example: App {
/// @Environment(\.openWindow) var openWindow
///
/// var body: some Scene {
/// ...
///
/// Window("Clipboard", id: "clipboard") {
/// ClipboardContentView()
/// }
/// .commandsReplaced {
/// CommandGroup(after: .pasteboard) {
/// Section {
/// Button("Show Clipboard") {
/// openWindow(id: "clipboard")
/// }
/// }
/// }
/// }
/// }
/// }
特定于查看菜单,基于Grimxn的答案,示例代码列表如下:
.commandsReplaced(content: {
CommandGroup(before: .toolbar) {
Section {
Button {
print("new command")
} label: {
Text("Full Screen")
}
}
}
})