6

I'd like to have an item in the macOS menubar that takes the whole height of the bar. This can be seen, for example, in FaceTime's UI:

enter image description here

In my attempts, I can only get the item to extend to 1pt away from the y edges of the menu bar:

enter image description here

(Note that in a menubar with a notch, even FaceTime won't extend to the edges, but it still extends 1pt further on the top and bottom than my versions).

I've tried both the NSStatusItem button and (deprecate) view to get things to work. I've also tried SwiftUI's MenuBarExtra

Simple example that leads to the second screenshot above:

final class StatusItemManager: ObservableObject {
    var statusButtonItem: NSStatusItem?
    var statusViewItem: NSStatusItem?
    
    /// Note that this uses deprecated APIs -- I'd prefer to stay away from these if possible
    func showViewStatusItem() {
        statusViewItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
        
        guard let statusViewItem else { return }
        
        let iconView = NSHostingView(rootView: ItemView(title: "View"))
                
        statusViewItem.view = iconView
        
        statusViewItem.view?.frame = NSRect(x: 0, y: 0, width: 50, height: 40)
    }
    
    /// Non-deprecated, but still not working
    func showButtonStatusItem() {
        statusButtonItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
        
        guard let statusButtonItem else { return }
        
        let iconView = NSHostingView(rootView: ItemView(title: "Button"))
        
        iconView.frame = NSRect(x: 0, y: 0, width: 50, height: 24)

        statusButtonItem.button?.addSubview(iconView)

        statusButtonItem.button?.action = #selector(menuBarButtonPressed)
        statusButtonItem.button?.target = self

        statusButtonItem.button?.frame = iconView.frame
    }
    
    struct ItemView: View {
        var title: String
        
        var body: some View {
            Text(title)
                .frame(maxWidth: .infinity, maxHeight: .infinity)
                .background(Color.green)
        }
        
    }
    
    @objc func menuBarButtonPressed(_ sender: Any?) {
        print("pressed")
    }
}

struct ContentView: View {
    @StateObject var manager = StatusItemManager()
    
    var body: some View {
        VStack {
            Image(systemName: "globe")
                .imageScale(.large)
                .foregroundColor(.accentColor)
            Text("Hello, world!")
        }
        .padding()
        .onAppear {
            manager.showButtonStatusItem()
            manager.showViewStatusItem()
        }
    }
}
jnpdx
  • 45,847
  • 6
  • 64
  • 94

0 Answers0