3
6

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でメニューバーアプリケーションを作成する(Xcode 13.1)

Posted at

サンプルはたくさんあるけれど・・・

Macのメニューバーに常駐するアプリケーションをSwiftUIで作るサンプルをいくつか探して試してみたのですが、現在のXcodeで作成できるSwiftアプリケーションのテンプレートだとうまくいかなかったため、さらにいろいろと駆けずり回ってどうにかサンプルが作れたので手順をメモしておきます。

プロジェクト作成

macOSアプリとして作成します。

スクリーンショット 2021-11-27 10.05.38.png

Interfaceを Storyboard で作成します。

スクリーンショット 2021-11-27 10.06.57.png

作成されたプロジェクト

スクリーンショット 2021-11-27 10.07.58.png

ストーリーボードの修正

Mainを開いて、Window Controller Scene を選択して、deleteキーで削除します。

スクリーンショット 2021-11-27 10.08.32.png

スクリーンショット 2021-11-27 10.10.21.png

アイコンの追加

Assetsを開いて、メニューバーに表示するアイコンを追加します。

スクリーンショット 2021-11-27 10.18.17.png

追加されたアイコン

スクリーンショット 2021-11-27 10.19.12.png

info.plistの修正

Application is agent (UIElement)YESに設定します。

スクリーンショット 2021-11-27 10.12.05.png

ソースの修正

StatusBarControllerの追加

メニューバーの表示&制御を行うコントローラを追加します。

StatusBarController.swift
import Foundation
import AppKit

class StatusBarController {
    private var statusBar: NSStatusBar
    private var statusItem: NSStatusItem
    private var popover: NSPopover
    
    init(_ popover: NSPopover) {
        self.popover = popover
        statusBar = NSStatusBar.init()
        // Creating a status bar item having a fixed length
        statusItem = statusBar.statusItem(withLength: 28.0)
        
        if let statusBarButton = statusItem.button {
            // 追加したアイコン名を設定
            statusBarButton.image = #imageLiteral(resourceName: "icon")
            statusBarButton.image?.size = NSSize(width: 18.0, height: 18.0)
            statusBarButton.image?.isTemplate = true            
            statusBarButton.action = #selector(togglePopover(sender:))
            statusBarButton.target = self
        }
    }
    
    @objc func togglePopover(sender: AnyObject) {
        if(popover.isShown) {
            hidePopover(sender)
        }
        else {
            showPopover(sender)
        }
    }
    
    func showPopover(_ sender: AnyObject) {
        if let statusBarButton = statusItem.button {
            popover.show(relativeTo: statusBarButton.bounds, of: statusBarButton, preferredEdge: NSRectEdge.maxY)
        }
    }
    
    func hidePopover(_ sender: AnyObject) {
        popover.performClose(sender)
    }
}

AppDelegateの修正

AppDelegate.swift
import Cocoa
import SwiftUI

@main
class AppDelegate: NSObject, NSApplicationDelegate {

    var popover = NSPopover.init()
    var statusBar: StatusBarController?

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

        // Set the SwiftUI's ContentView to the Popover's ContentViewController
        popover.contentSize = NSSize(width: 360, height: 360)
        popover.contentViewController = NSHostingController(rootView: contentView)
        
        // Create the Status Bar Item with the above Popover
        statusBar = StatusBarController.init(popover)
    }

    func applicationWillTerminate(_ aNotification: Notification) {
        // Insert code here to tear down your application
    }
}

Viewを作成する

メニューバーに表示されたアイコンをクリックしたときに表示する画面を作成します。

ContentView.swift

import SwiftUI

struct ContentView: View {
    var body: some View {
        Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
            .background(Color.yellow)
            .foregroundColor(Color.blue)
            .frame(width: 300, height: 150)
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

実行結果

実行した結果です(暗くてわかりずらいですが)

menubar.gif

まとめ

SwiftUIによる画面の開発が容易になったため、iOSだけでなくMacOSでなにかアプリを作ってみようかなと思いメニューバーアプリケーションとしてユーティリティーの作り方をいろいろと調べてみたのですが、年代やらXcodeのバージョンによっていろいろと作りが変わるようで、だいぶ沼化しました。

この作り方ももしかしたら他のやり方があるのかもしれませんが、どなたかのモチベーションを刺激できたら幸いですw

今回のサンプルはGitHubでも公開しています。
https://github.com/6in/MenuBarAppSample

3
6
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
3
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?