I'm trying to create a simple menu bar extra in Swift UI using the new MenuBarExtra. I would like the button text in the popover to update dynamically every time the menu is open.
I'm creating the MenuBarExtra like this.

MenuBarExtra("Example menu title") {
Button("Item 1") {
}
Button("Item 2") {
}
Button("Item 3") {
}
}
I would like the button text (ie. Item 1) to change every time the menu is open. I would have expected onAppear to fire every time the menu is open, but it only fires the first time. After the initial opening of the popover, there is no clear way to detect a menu close or open event.
I have tried using the various event handling callbacks to detect the popover opening. OnAppear works for detecting the initial creation of the view while onDisappear is notably never called.
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")
}
}
I happend to do some thing like this, and I find some solution like this:
I passed appDelegate use .environmentObject(appDelegate) to a MenuBarView.
In the MenuBarView, use @EnvironmentObject to bind the view, and then I maintain the menu list data for the MenuBarView in AppDelegate
Some demo code:
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) {}
}
}
}
After all this setup, you can then maintain the appDelegate.menuItems in AppDelegate programmatically, and the MenuBarView will update automatically.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With