Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to handle lifecycle events for MenuBarExtra in macOS 13 SwiftUI

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.

enter image description here

        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")
        }
    }
like image 712
Lukas Valine Avatar asked Jan 30 '26 10:01

Lukas Valine


1 Answers

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.

like image 138
Alex Avatar answered Feb 01 '26 00:02

Alex



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!