如何在 SwiftUI 中激活/停用菜单项

Posted

技术标签:

【中文标题】如何在 SwiftUI 中激活/停用菜单项【英文标题】:How to activate / deactivate menu items in SwiftUI 【发布时间】:2021-01-18 02:30:26 【问题描述】:

我正在尝试在 Mac os 的 SwiftUI 应用程序中创建自定义菜单项(SwiftUI 应用程序生命周期)。我不太明白以下行为:

在下面的代码中:

import SwiftUI
@main
struct mysqltoolApp: App 
    @ObservedObject var mysql = MySQL()
    var flags = UtilFlags()
    var selectedDB = "mysql"
    var body: some Scene 
        let mainWindow = WindowGroup(Text("title")) 
            ContentView()
                .environmentObject(mysql)
                .environmentObject(flags)
        
        .windowStyle(HiddenTitleBarWindowStyle())
        .commands 
            CommandMenu("Tools", content: 
                    Button("Connect...", action: flags.connectDialogVisibilityFlag = true ).disabled(mysql.connected)
                    Button("Disconnect", action:  mysql.closeBase()
                            mysql.connected = false).disabled(!mysql.connected)
            )
            CommandGroup(after: .help, addition: 
                Button("Test button", action: print("Test button pressed"))
                .disabled(!mysql.connected)
            )
        
        return mainWindow
    

通过 CommandMenu 添加的按钮的行为符合预期(即根据 'mysql.connected' 的更改值激活和停用。通过 CommandGroup 添加的按钮在启动时根据 'mysql.connected' 的值正确配置,但是忽略 'mysql.connected' 的变化,并没有改变它的状态。我错过了什么?

我重写了上面的部分来强调这个问题。简而言之:

import SwiftUI

@main
struct MenuTestApp: App 
    @State var active = false
    var body: some Scene 
        WindowGroup 
            ContentView()
        
        .commands(content: 
            CommandMenu("Tools", content: 
                Button("Normally active", action: active = !active).disabled(active)
                Button("Normally inactive", action: active = !active).disabled(!active)
            )
            CommandGroup(after: .newItem, addition: 
                Button("Normally active", action: active = !active).disabled(active)
                Button("Normally inactive", action: active = !active).disabled(!active)
            )
        )
    

通过 CommandMenu 添加的按钮行为正确(根据 'active' 的值激活和停用。通过 CommandGroup 添加的按钮忽略 'active' 的值并保持其初始状态。

【问题讨论】:

【参考方案1】:

我在 Apple 开发中得到了一个很好的建议。论坛(感谢 OOPer!)。它可能无法解决根本原因(它是 SwiftUI 中的错误吗?),但它提供了一个很好的解决方法。如果我将“行为不端”按钮包装到视图中并添加它,一切都会按预期工作:

import SwiftUI
@main
struct MySQLtoolApp: App 
    @StateObject var mysql = MySQL()
    var flags = UtilFlags()
    var selectedDB = "mysql"
    var body: some Scene 
        let mainWindow = WindowGroup(Text("title")) 
            ContentView()
                .environmentObject(mysql)
                .environmentObject(flags)
        
        .windowStyle(HiddenTitleBarWindowStyle())
        .commands 
            CommandMenu("Tools", content: 
                    Button("Connect...", action: flags.connectDialogVisibilityFlag = true ).disabled(mysql.connected)
                    Button("Disconnect", action:  mysql.closeBase()
                            mysql.connected = false).disabled(!mysql.connected)
            )
            CommandGroup(after: .newItem, addition: 
                MyButtonsGroup().environmentObject(mysql)
            )
        
        return mainWindow
    

struct MyButtonsGroup: View 
    @EnvironmentObject var mysql: MySQL
    var body: some View 
        Button("Test button", action: print("Test button pressed"))
            .disabled(mysql.connected)
    

【讨论】:

一个奇怪的错误。我的 CommanGroups 在 AppDelegate 中按预期工作...

以上是关于如何在 SwiftUI 中激活/停用菜单项的主要内容,如果未能解决你的问题,请参考以下文章

如何将多个功能/选项发送到多个列表项?

如何在 SwiftUI 中以降低透明度为菜单项获取 AccentColor 背景?

SwiftUI:如何在 macOS 应用程序中实现编辑菜单

为啥我的菜单项会激活滚动功能?

当光标离开激活项时,工具条菜单项会自行更改颜色

菜单栏中的菜单项未激活,无法选择或单击