feed

2022年11月03日, 編集履歴

SwiftUI macOSアプリでメニューバーエクストラを出す

macOSのメニューバーエクストラは、画面最上部のメニューバー右側に配置されるアイコンであり、それをクリックする事でメニューあるいはポップオーバーを表示し、アプリ等が最前面になくとも機能を呼び出せるUIである。常駐アプリ等で設定変更や状態確認のために使われることが多い。

SwiftUI macOSアプリでメニューバーアイコンを出すにはMenuBarExtraを使う。

文字列表示

メニューバーエクストラに文字列として項目を表示したい場合は、

@main
struct MenuBarExtraSampleApp: App {
  var body: some Scene {
    MenuBarExtra("MenuBarExtra") {
      Button("About App") {
        NSApp.orderFrontStandardAboutPanel(nil)
        NSApp.activate(ignoringOtherApps: true)
      }
      Button("Settings...") {
        NSApp.sendAction(Selector(("showSettingsWindow:")), to: nil, from: nil)
        NSApp.activate(ignoringOtherApps: true)
      }
      Divider()
      Button("Quit App") {
        NSApp.terminate(nil)
      }
    }
  }
}

のようにする。この例ではメニュー形式のメニューバーエクストラが作られる。

アイコン表示

アイコンを表示する場合は、

MenuBarExtra("MenuBarExtra", image: "icon") {
  ...
}

や、

MenuBarExtra("MenuBarExtra", systemImage: "star.fill") {
  ...
}

とする。このとき、第一引数の文字列は表示されなくなる。

アイコンと文字列表示

アイコンも文字列も両方出したい場合は、

MenuBarExtra {
  ...
} label: {
  Label("MenuBarExtra", systemImage: "star.fill")
    .labelStyle(.titleAndIcon)
}

とする。ここで単にLabelだけだとやはり文字列が表示されない。.labelStyle(.titleAndIcon)を指定することでアイコンと文字列両方が表示される。

ポップオーバー表示

通常はメニュー形式で表示されるメニューバーエクストラだが、ポップオーバー形式にすることもできる。その場合は、

MenuBarExtra("MenuBarExtra") {
  HStack {
    Image(systemName: "heart.fill")
    Button("MenuBarExtra") {}
    Image(systemName: "heart.fill")
  }
  .frame(width: 300, height: 200)
}
.menuBarExtraStyle(.window)

のようにmenuBarExtraStyleを使う。

メニューバーエクストラの表示・非表示切り替え

メニューバーエクストラの表示・非表示の切り替えをしたい場合はisInsertedが入っているイニシャライザを使う。

@main
struct StatusBarSampleApp: App {

  @AppStorage("MenuBarExtraShown") private var menuBarExtraShown = true

  var body: some Scene {
    MenuBarExtra("MenuBarExtra", systemImage: "star.fill", isInserted: $menuBarExtraShown) {
      ...
    }
  }
}

この場合、どこかのビューで、

struct GeneralSettingsView: View {

  @AppStorage("MenuBarExtraShown") private var menuBarExtraShown: Bool = true

  var body: some View {
    Form {
      Toggle("Menu Bar Extra", isOn: $menuBarExtraShown)
    }
    .padding()
  }
}

のように切り替えをするUIを用意する。

常駐アプリ化

メインウィンドウを持たずにメニューバーエクストラを操作の起点とするような常駐アプリにしたい場合は、ターゲットの「Info」欄で「Application is agent (UIElement)」を「YES」にする。こうすることで、アプリがDockやAppスイッチャーに表示されなくなる。