如何在 macOS 13 SwiftUI 中处理 MenuBarExtra 的生命周期事件

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

我正在尝试使用新的 MenuBarExtra 在 Swift UI 中创建一个额外的简单菜单栏。我希望弹出窗口中的按钮文本在每次打开菜单时动态更新。

我正在像这样创建 MenuBarExtra。

        MenuBarExtra("Example menu title") {
            Button("Item 1") {
              
            }
            
            Button("Item 2") {
              
            }
            
            Button("Item 3") {
              
            }
        }

我希望每次打开菜单时更改按钮文本(即第 1 项)。我本以为每次打开菜单时都会触发 onAppear,但它只会在第一次触发。弹出窗口初始打开后,没有明确的方法来检测菜单关闭或打开事件。

我尝试使用各种事件处理回调来检测弹出窗口的打开。 OnAppear 用于检测视图的初始创建,而 onDisappear 从未被调用过。

    MenuBarExtra("Example menu title") {
        VStack {
            Button("Item 1") {
                
            }
            
            Button("Item 2") {
                
            }
            
            Button("Item 3") {
                
            }
        }.onAppear() {
            print("This only prints the very first time the menu is opened")
        }
    }
swift swiftui menubar macos-ventura
2个回答
1
投票

According to Apple's Docs,

MenuBarExtra
conforms to
Scene
- 这意味着您可以使用
Environment
变量
ScenePhase
每次 MenuBarExtra 进入前景或背景时调用一些东西。文章来源:https://www.hackingwithswift.com/quick-start/swiftui/how-to-detect-when-your-app-moves-to-the-background-or-foreground-with-scenephase。用法示例:

@main
struct AppWithMenuBarExtra: App {
@Environment(\.scenePhase) var scenePhase // <-- HERE! This will give you the values

    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        MenuBarExtra(
            "App Menu Bar Extra", systemImage: "star")
        {
            StatusMenu()
.onChange(of: scenePhase) { newPhase in //<-- HERE TOO! This modifier allows you to detect change of scene.
                if newPhase == .inactive {
                    //Code for moved to inactive
                    print("Moved to inactive")
                } else if newPhase == .active {
                    //Code for moved to foreground
                    print("Moved to foreground - now active")
                    //This is where you would want to change your text
                } else if newPhase == .background {
                    //Code for moved to background
                    print("Moved to background")
                }
            }
        }
    }
}

0
投票

我碰巧做了这样的事情,我找到了这样的解决方案:

我通过了

appDelegate
使用
.environmentObject(appDelegate)
MenuBarView
。 在
MenuBarView
中,使用
@EnvironmentObject
绑定视图,然后我在
MenuBarView
中为
AppDelegate

维护菜单列表数据

一些演示代码:

App.swift

import SwiftUI
@main
struct MyApp: App {
    @NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate

    var body: some Scene {
        MenuBarExtra("Example menu title") {
            MenuBarView().environmentObject(appDelegate)
        }
    }
}

AppDelegate.swift

import AppKit
import SwiftUI

final class AppDelegate: NSObject, NSApplicationDelegate, ObservableObject {
    @Published var menuItems: [String] = []

    func applicationDidFinishLaunching(_ notification: Notification) {
        // build menuItems here or somewhere
        menuItems = ["Item 1", "Item 2"]
    }
}

MenuBarView.swift

import SwiftUI
struct MenuBarView: View {
    @EnvironmentObject var appDelegate: AppDelegate
    var body: some View {
        ForEach(appDelegate.menuItems) { menuItem in
            Button(menuItem) {}
        }
    }
}

完成所有这些设置后,您可以以编程方式维护

appDelegate.menuItems
中的
AppDelegate
,MenuBarView将自动更新。

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