簡體   English   中英

隱藏 SwiftUI / MacOS 應用程序的編輯菜單

[英]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) { }
    }

對於本機 (Cocoa) 應用程序

可以使用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 (UIKit) 應用程序

對於基於 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。)

對於那些正在尋找任何更新的人 - 看看我問過的這個問題(並自己回答):

SwiftUI 更新主菜單 [已解決] kludgey

我解決它的方法是將它放在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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM