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

问题描述 投票:0回答:3

我正在创建一个

NSViewRepresentable
视图以在 SwiftUI 代码中使用
NSView
。 我需要
NSViewRepresentable
代码来通过
NSApp.mainMenu
属性自定义应用程序的主菜单。

但事实证明,该任务的合格 AppKit 代码在 SwiftUI 环境中不起作用。通过调试主菜单,我看到添加到菜单的项目出现在 NSMenu 实例中,但这些项目没有显示在 SwiftUI 应用程序菜单中,但它们显示在 AppKit 应用程序菜单中。

调试显示,在 SwiftUI 环境中,应用程序的主菜单使用

SwiftUI.AppKitMainMenuItem
对象而不是
NSMenuItem
。但它是苹果的私人课程我不能使用。

在SwiftUI环境下如何实现?我确实需要在 NSViewRepresentable 类中使用 Cocoa 代码库来完成此操作,因为我正在为 AppKit、UIKit 和 SwiftUI 开发通用扩展。

swift macos swiftui
3个回答
1
投票

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
App 的结构中。要生成自定义菜单项,请使用
.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

1
投票

我也研究过这个问题 - 这可能是 swiftUI 上的一个错误,一直破坏菜单。

无论如何 - 看看这个线程: SwiftUI 更新主菜单 [已解决] kludgey

将其放入

DispatchQueue.main.async
函数中的
AppDelegate.applicationWillUpdate
闭包中

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!)
            }
        }
    }
}

0
投票

据我了解,我需要在 App 结构中使用 CommandGroup 在 SwiftUI 中设置菜单项。所以我有以下内容。

import SwiftUI

@main
struct Oh_My_App: App {
    var body: some Scene {
        WindowGroup {
            ContentView(menuObservable: menuObservable)
        }
        .commands {
            CommandGroup(replacing: .systemServices){
                
            }
            CommandMenu("Help") {
                Button("Button 1", action: {
                   
                } )
                .keyboardShortcut("N")
                Divider()
                Button("Button 2", action: {
                   
                } )
                .keyboardShortcut("S")
                Divider()
                Button("Button 3", action: {
                   
                } )
                .keyboardShortcut("R")
            }
        }
  }
}

CommandGroup(replacing: .systemServices) 行将默认的“服务”菜单替换为空组,从而有效地删除了默认项目。如果您想覆盖或删除内置菜单命令,这会很有用。

使用 CommandMenu("Help") 将名为“Help”的新自定义菜单部分添加到应用程序的菜单栏中。 在此菜单中,定义了三个按钮: “按钮 1”带有键盘快捷键“N”。 “按钮 2”带有键盘快捷键“S”。 “按钮 3”带有键盘快捷键“R”。 每个按钮都有一个关联的操作块,该块当前为空。这些块可以填充自定义功能。 Divider() 元素用于在视觉上分隔按钮,增强菜单的布局。

如果您想删除所有默认菜单项。这是最好的方法:

class AppDelegate: NSObject, NSApplicationDelegate {
    
    func applicationDidFinishLaunching(_ aNotification: Notification) {
        setupMenuBar()
    }

    private func setupMenuBar() {
            
            if let mainMenu = NSApplication.shared.mainMenu {
                mainMenu.items.enumerated().forEach { index, item in
                    if index != 0 && index != 4 {
                        item.isHidden = true
                    }
                }
            }
            
        }

}

它将删除所有 5 个默认主菜单项。

© www.soinside.com 2019 - 2024. All rights reserved.