67
62

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

SwiftUI で MacOS メニューバーアプリケーションを手軽に開発

Last updated at Posted at 2021-01-22

SwiftUI を使えば、メニューバーアプリケーションを簡単に開発できます。

メニューバーアプリケーションを設置することで、最上部システムバーにアプリケーションが表示され、ユーザーはこのアイコンをクリックしてアプリケーションのポップオーバー表示にすばやくアクセスできるようになります。

アプリレビューを待つ間に、システムバー内でタスクリストを管理できる小さな TODO アプリケーションを最近開発しました。ソースコードをダウンロードして仕組みを確認することができます。
https://github.com/mszmagic/MenuBarTODO
https://apps.apple.com/jp/app/menubartodo/id1550343840?mt=12

MacOSアプリケーションの作成

まず、SwiftUIを有効にした空のMacOSアプリケーションを作成します。アプリケーションの種類として AppKit App Delegate を選択していることを確認してください。

スクリーンショット 0003-01-22 15.35.41.png

AppDelegate.swift ファイルの設定

メニューバーアイテムとポップオーバーウィンドウをこのファイルで設定する必要があります。この記事では、ContentView() をポップアップウィンドウとして使用します。

アプリケーションで一般的なインターフェースも使用したい場合には、ポップアップウィンドウ専用の個別のSwiftUIビューを作成する必要があります。

変数の設定

以下の変数を AppDelegate.swift ファイルに追加:

var statusBarItem: NSStatusItem!
var popover: NSPopover!

ステータスバーのアイテムを初期化する

statusBarItem は、システムのメニューバーに表示される項目です。このオブジェクトをイメージ(またはシステムイメージ)で初期化する必要があります。

self.statusBarItem = NSStatusBar.system.statusItem(withLength: CGFloat(NSStatusItem.variableLength))
guard let button = self.statusBarItem.button else { return }
button.image = NSImage(systemSymbolName: "checkmark.circle.fill", accessibilityDescription: nil)
button.action = #selector(showHidePopover(_:))

この記事の次の部分で showHidePopover 関数を定義します。

ポップオーバーを初期化する

ここで、ポップオーバーウィンドウを初期化して、そのウィンドウのコンテンツとなるSwiftUIのビューを設定する必要があります。

let popover = NSPopover()
popover.contentSize = NSSize(width: 350, height: 500)
popover.behavior = .transient
let contentView = ContentView().environment(\.managedObjectContext, persistenceController.storageContext)
popover.contentViewController = NSHostingController(rootView: contentView)
self.popover = popover

ユーザーがメニュー項目をクリックした際にポップオーバーを表示または非表示

また、ポップオーバーを表示または非表示にする機能 showHidePopover も定義する必要があります。

@objc func showHidePopover(_ sender: AnyObject?) {
    guard let button = self.statusBarItem.button else { return }
    if self.popover.isShown {
        self.popover.performClose(sender)
    } else {
        self.popover.show(relativeTo: button.bounds, of: button, preferredEdge: NSRectEdge.minY)
        self.popover.contentViewController?.view.window?.becomeKey()
    }
}

プログラムを実行する

これでプログラムが実行できます。システムメニューバーに新しいメニュー項目が表示されるはずです。

システムメニューバーにしか表示されないアプリケーションの作成

Xcodeでプロジェクトを作成すると、XcodeではSwiftUIのビューがウィンドウに表示されます。

func applicationDidFinishLaunching(_ aNotification: Notification) {
    // Create the SwiftUI view that provides the window contents.
    let contentView = ContentView()

    // Create the window and set the content view.
    window = NSWindow(
        contentRect: NSRect(x: 0, y: 0, width: 480, height: 300),
        styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView],
        backing: .buffered, defer: false)
    window.isReleasedWhenClosed = false
    window.center()
    window.setFrameAutosaveName("Main Window")
    window.contentView = NSHostingView(rootView: contentView)
    window.makeKeyAndOrderFront(nil)
}

window 変数を削除し、applicationDidFinishLaunching 関数内のすべての関連コードを削除する(メニュー項目とポップオーバーを初期化するためのコードは保持します)ことで、アプリケーションをシステムメニューバーでのみ表示するようにできます。

func applicationDidFinishLaunching(_ aNotification: Notification) {
    let contentView = ContentView()
    // ...
}

また、システムがアプリケーションウィンドウの表示を試みないようにするには、Info.plistファイル内のLSUIElementYESに設定する必要があります。

スクリーンショット 0003-01-22 14.39.28.png

ところでそのアプリケーションは、システムメニューバーにのみ表示され、アプリケーションウィンドウは表示しません。

Githubのこちらのデモプロジェクトをご覧ください。上記のコードが含まれています。
https://github.com/mszmagic/MenuBarTODO


:relaxed: Twitter @MszPro

:sunny: 私の公開されているQiita記事のリストをカテゴリー別にご覧いただけます。

67
62
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
67
62

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?