在 SwiftUI 环境中自定义应用程序的主菜单



我正在创建一个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!)
}
}
}
}

最新更新