17

Create a mac menu bar app in SwiftUI with MenuBarExtra

 2 years ago
source link: https://sarunw.com/posts/swiftui-menu-bar-app/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Create a mac menu bar app in SwiftUI with MenuBarExtra

16 Jun 2022 ⋅ 4 min read ⋅ macOS WWDC22


Table of Contents

In the previous post on How to make a macOS menu bar app, we learn how to make a mac menu bar app in AppKit.

This year in WWDC22 with iOS 16, Apple made it easy to create a menu bar app in SwiftUI.

I will replicate the toy app we created in How to make a macOS menu bar app using SwiftUI.

This is what the final result looks like.
It is an app that shows a number from 1 to 3, and you change it by tapping it and selecting the new number from the menu item.

The final result of our menu bar app.

The final result of our menu bar app.

You can easily support sarunw.com by checking out this sponsor.

Reliable mobile testing for iOS apps:

Sponsor sarunw.com and reach thousands of iOS developers.

How to make a mac menu bar app in SwiftUI

We need to do three things to create a mac menu app.

Create a macOS project

Let's start by creating a new macOS project.

Select File > New > Project... then select App under macOS platform.

New macOS project.

New macOS project.

Add a menu bar extra

A menu bar extra is the name for a menu bar that sits in the trailing end of the menu bar.

This is where we want to put a menu bar for a utility app.

We can easily add this with a new Scene called MenuBarExtra.

import SwiftUI

@main
struct swiftui_menu_barApp: App {
// 1
@State var currentNumber: String = "1"

var body: some Scene {
WindowGroup {
ContentView()
}
// 2
MenuBarExtra(currentNumber, systemImage: "\(currentNumber).circle") {
// 3
Button("One") {
currentNumber = "1"
}
Button("Two") {
currentNumber = "2"
}
Button("Three") {
currentNumber = "3"
}
}
}
}

1 We want our menu bar label to be changable based on user selection, so we create a state variable to keep the current number selection.
2 MenuBarExtra scene with a SF Symbols as a label. It can rotate between "1.circle", "2.circle", and "3.circle" based on user selection.
3 We populate our menu bar with three buttons which will render as a menu item. In the action, we change currentNumber which in-turn change the menu bar label.

With these few lines of code, we got a menu bar extra working.

A menu bar app with three items.

A menu bar app with three items.

Add a keyboard shortcut to each menu item

We can add a keyboard shortcut to a button using the .keyboardShortcut view modifier.

import SwiftUI

@main
struct swiftui_menu_barApp: App {
@State var currentNumber: String = "1"

var body: some Scene {
WindowGroup {
ContentView()
}
MenuBarExtra(currentNumber, systemImage: "\(currentNumber).circle") {
Button("One") {
currentNumber = "1"
}
.keyboardShortcut("1")
Button("Two") {
currentNumber = "2"
}
.keyboardShortcut("2")
Button("Three") {
currentNumber = "3"
}
.keyboardShortcut("3")
}
}
}

Keyboard shortcuts are usually composed of modifier keys, e.g., command, and another key, e.g., c, to form a shortcut.

.keyboardShortcut has a default .command modifier, so we don't need to specify that. We only need to specify a key that works with a command key.

The result shortcut key would be ⌘1, ⌘2, and ⌘3.

Add keyboard shortcuts with .keyboardShortcut modifier.

Add keyboard shortcuts with .keyboardShortcut modifier.

Add a way to quit

The final act is to add a way for users to quit your app.

This is just a matter of adding another button.

@main
struct swiftui_menu_barApp: App {
@State var currentNumber: String = "1"

var body: some Scene {
WindowGroup {
ContentView()
}
MenuBarExtra(currentNumber, systemImage: "\(currentNumber).circle") {
Button("One") {
currentNumber = "1"
}
.keyboardShortcut("1")
Button("Two") {
currentNumber = "2"
}
.keyboardShortcut("2")
Button("Three") {
currentNumber = "3"
}
.keyboardShortcut("3")
Divider()
Button("Quit") {
NSApplication.shared.terminate(nil)
}.keyboardShortcut("q")
}
}
}

We add a divider to separate the primary function from the quit menu. I use NSApplication.shared.terminate(nil) as a way to quit the app (not sure if there is a more SwiftUI way to doing this or not).

With this last change, we have a working menu bar app.

A menu bar app.

A menu bar app.

Now, it is time to clean up unused code. We need to do two things.

Remove the main window

To remove the main window app, we remove WindowGroup from <ProjectName>App.swift.

A boilerplate app.

A boilerplate app.

@main
struct swiftui_menu_barApp: App {
@State var currentNumber: String = "1"

var body: some Scene {
// Remove this
// WindowGroup {
// ContentView()
// }
MenuBarExtra(currentNumber, systemImage: "\(currentNumber).circle") {
Button("One") {
currentNumber = "1"
}
.keyboardShortcut("1")
Button("Two") {
currentNumber = "2"
}
.keyboardShortcut("2")
Button("Three") {
currentNumber = "3"
}
.keyboardShortcut("3")
Divider()
Button("Quit") {
NSApplication.shared.terminate(nil)
}.keyboardShortcut("q")
}
}
}

You can easily support sarunw.com by checking out this sponsor.

Reliable mobile testing for iOS apps:

Sponsor sarunw.com and reach thousands of iOS developers.

Remove the dock icon

Even though we remove the main window scene, the app icon still shows in the Dock or the application switcher.

App icon still shows in the Dock.

App icon still shows in the Dock.

It is common for the menu bar app not to show that.

To remove the Dock icon.

  1. open Info.plist or open up the Info tab under your app target.
  2. Then add a new key "Application is agent (UIElement)" (LSUIElement flag), and sets the value to YES.

Set

Set "Application is agent (UIElement)" to Yes.

And that's all you need to do to create a menu bar app on macOS with SwiftUI.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK