我正在创建一个NSViewRepresentable
视图,以便在SwiftUI代码中使用NSView
。我需要NSViewRepresentable
代码来通过NSApp.mainMenu
属性自定义应用程序的主菜单。
但事实证明,该任务的合格AppKit代码在SwiftUI环境中不起作用。通过调试主菜单,我看到我添加到菜单中的项目显示在NSMenu实例中,但这些项目没有显示在SwiftUI应用程序菜单中,但它们显示在AppKit应用程序菜单上。
调试显示,在SwiftUI环境中,应用程序的主菜单使用SwiftUI.AppKitMainMenuItem
对象而不是NSMenuItem
。但这是苹果公司的私人课程,我不能使用。
如何在SwiftUI环境中实现这一点?我真的需要在NSViewRepresentable类中使用Cocoa代码库来完成这项工作,因为我正在开发AppKit、UIKit和SwiftUI的通用扩展。
SwiftUI macOS主菜单
Xcode 14.0+,macOS蒙特利12.5.1
要从主菜单中删除所有五个默认菜单项,请使用以下方法:
import SwiftUI
class AppDelegate: NSObject, NSApplicationDelegate {
func applicationDidFinishLaunching(_ aNotification: Notification) {
let menus = ["File","Edit","View","Window","Help"]
menus.forEach { menu in
NSApp.mainMenu?.item(withTitle: menu).map {
NSApp.mainMenu?.removeItem($0)
}
}
}
}
然后将@NSApplicationDelegateAdaptor属性包装器放入SwiftUI@main
应用程序的结构中。要生成自定义菜单项,请使用.commands {...}
修饰符。
@main struct YourApp: App {
@NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
WindowGroup {
ContentView()
}
.commands {
CommandMenu("Custom") {
Button("Add Item", action: { } )
.keyboardShortcut("N")
Divider()
Button("Edit Item", action: { } )
.keyboardShortcut("E")
}
}
}
}
或者,您可以将@NSApplicationDelegateAdaptor
属性包装器放置在ContentView
结构中,而不是YourApp
@main结构中。
@NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
我也对此进行了研究——这可能是swiftUI上的一个错误,它一直在破坏菜单。
无论如何,看看这个帖子:SwiftUI更新主菜单[SOLVED]kludgey
将其放入AppDelegate.applicationWillUpdate
函数中的DispatchQueue.main.async
闭包中
import Foundation
import AppKit
public class AppDelegate: NSObject, NSApplicationDelegate {
public func applicationWillUpdate(_ notification: Notification) {
DispatchQueue.main.async {
let currentMainMenu = NSApplication.shared.mainMenu
//
// Do your menu stuff here
//
// The below removes the Edit menu
//
let editMenu: NSMenuItem? = currentMainMenu?.item(withTitle: "Edit")
if nil != editMenu {
NSApp.mainMenu?.removeItem(editMenu!)
}
}
}
}