[英]Hiding Edit Menu of a SwiftUI / MacOS app
我的 MacOS 应用程序没有任何文本编辑功能。 如何隐藏自动添加到我的应用程序的Edit
菜单? 我更愿意在 SwiftUI 中进行此操作。
我希望下面的代码应该可以工作,但事实并非如此。
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}.commands {
CommandGroup(replacing: .textEditing) {}
}
}
}
据我所知,你不能隐藏整个菜单,你可以隐藏其中的元素组:
.commands {
CommandGroup(replacing: .pasteboard) { }
CommandGroup(replacing: .undoRedo) { }
}
可以使用NSApplicationDelegate
删除应用程序菜单。 这种方法可能会在未来的 macOS 版本中中断(例如,如果编辑菜单的位置发生变化),但目前确实有效:
class MyAppDelegate: NSObject, NSApplicationDelegate, ObservableObject {
let indexOfEditMenu = 2
func applicationDidFinishLaunching(_ : Notification) {
NSApplication.shared.mainMenu?.removeItem(at: indexOfEditMenu)
}
}
@main
struct MyApp: App {
@NSApplicationDelegateAdaptor private var appDelegate: MyAppDelegate
var body: some Scene {
WindowGroup {
ContentView()
}.commands {
// ...
}
}
}
对于基于 Catalyst 的 macOS 应用程序,该方法与上述方法类似,只是使用了从UIResponder
派生的UIApplicationDelegate
:
class MyAppDelegate: UIResponder, UIApplicationDelegate, ObservableObject {
override func buildMenu(with builder: UIMenuBuilder) {
/// Only operate on the main menu bar.
if builder.system == .main {
builder.remove(menu: .edit)
}
}
}
@main
struct MyApp: App {
@UIApplicationDelegateAdaptor private var appDelegate: MyAppDelegate
var body: some Scene {
WindowGroup {
ContentView()
}.commands {
// ...
}
}
}
当 SwiftUI 更新窗口的主体时,当前的建议对我来说失败了。
解决方案:
使用 KVO 并观察NSApp
以了解\.mainMenu
上的更改。 在 SwiftUI 轮到它之后,你可以删除任何你想要的东西。
@objc
class AppDelegate: NSObject, NSApplicationDelegate {
var token: NSKeyValueObservation?
func applicationDidFinishLaunching(_ notification: Notification) {
// Remove a single menu
if let m = NSApp.mainMenu?.item(withTitle: "Edit") {
NSApp.mainMenu?.removeItem(m)
}
// Remove Multiple Menus
["Edit", "View", "Help", "Window"].forEach { name in
NSApp.mainMenu?.item(withTitle: name).map { NSApp.mainMenu?.removeItem($0) }
}
// Must remove after every time SwiftUI re adds
token = NSApp.observe(\.mainMenu, options: .new) { (app, change) in
["Edit", "View", "Help", "Window"].forEach { name in
NSApp.mainMenu?.item(withTitle: name).map { NSApp.mainMenu?.removeItem($0) }
}
// Remove a single menu
guard let menu = app.mainMenu?.item(withTitle: "Edit") else { return }
app.mainMenu?.removeItem(menu)
}
}
}
struct MarblesApp: App {
@NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some View {
//...
}
}
想法:
SwiftUI 要么有错误,要么他们真的不希望您删除NSApp.mainMenu
中的顶级菜单。 SwiftUI 似乎重置了整个菜单,目前无法覆盖或自定义大多数细节(Xcode 13.4.1)。 CommandGroup(replacing: .textEditing) { }
-esque 命令不允许您删除或清除整个菜单。 分配一个新的NSApp.mainMenu
只会在 SwiftUI 需要时被破坏,即使你没有指定任何命令。
这似乎是一个非常脆弱的解决方案。 应该有办法告诉 SwiftUI 不要触摸NSApp.mainMenu
或启用更多自定义。 或者 SwiftUI 似乎应该检查它是否拥有上一个菜单(菜单项是SwiftUI.AppKitMainMenuItem
)。 或者我错过了他们提供的一些工具。 希望这在 WWDC 测试版中得到修复?
(在带有 Swift 5 的 Xcode 13.4.1 中,针对没有 Catalyst 的 macOS 12.3。)
对于那些正在寻找任何更新的人 - 看看我问过的这个问题(并自己回答):
我解决它的方法是将它放在AppDelegate
applicationWillUpdate
function 的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
let editMenu: NSMenuItem? = currentMainMenu?.item(withTitle: "Edit")
if nil != editMenu {
NSApp.mainMenu?.removeItem(editMenu!)
}
}
}
}
我花了整整 4 天的时间搜索和尝试 :) - 通常归结为 2 行代码更改
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.