繁体   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