[英]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.