先日、Mac OSXでメニューバー(ステータスバー)に常駐するアプリケーションの作り方を紹介しました。
その記事では、テキストが表示される常駐アプリだったのですが、アイコンをクリックするとViewがポップアップ表示される常駐アプリを作ることもできるので紹介します。
もくじ
はじめに
今回作成する常駐アプリケーションは、クリックされるとポップアップウィンドウが開くというものになっています。
まずは、実際の動作を確認してください。
Sampleという常駐アプリを実行し、アプリアイコンをクリックした時の動作です。
アイコンをクリックすることで、このようなウィンドウがポップアップされるようなアプリケーションになっています。
ポップアップ表示のされ方や、実際の動作などは以下の動画を確認してみてください。
完成例
例えば、メニューバーの常駐アイコンをクリックしたら、以下のようなウィンドウがポップアップするようにしてみました。
「Change Color」というボタンをクリックすると「Hello World!!」の色が変わるという単純なアプリケーションです。
このようなアプリケーションが簡単に作成できるのですが、注意点もあります。
注意点については後述しますが、重要な内容になっていますので確認するようにしてください。
CustomViewController.xlb
アイコンがクリックされてウィンドウが表示されても、ポップアップで表示される項目がなくては意味がありませんよね。
ポップアップで表示されるウィンドウの中身はCustomViewで配置することができます。
xcodeの上部メニューから File > New > Fileと進んでください。
以下の画像を参考にして、Viewを新たに作成しましょう。
ここで作成するViewの名前は「CustomViewController」にしておいてください。
(この後紹介するコードで指定しているため)
CustomViewController.xlbが作成できたら、この中にLabelやButtonなどを配置してみましょう。
では「アイコンがクリックされたらCustomViewを表示」させるコードを書いていきます。
AppDelegateを編集
今回はメニューバーアプリからテキストを表示した時と同じように「AppDelegate.swift」を編集します。
デフォルトの状態だと、以下のようになっていると思いますので、早速編集してしまいましょう。
import Cocoa
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
func applicationDidFinishLaunching(_ aNotification: Notification) {
// Insert code here to initialize your application
}
func applicationWillTerminate(_ aNotification: Notification) {
// Insert code here to tear down your application
}
}
このような内容のAppDelegateに、メニューバー常駐アプリをポップアップ表示させるための処理を記述していきます。
今回は以下のようになりました。
import Cocoa
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
var statusItem = NSStatusBar.system().statusItem(withLength: NSVariableStatusItemLength)
let popover = NSPopover()
func applicationDidFinishLaunching(_ aNotification: Notification) {
// Insert code here to initialize your application
statusItem.title = "Sample"
statusItem.action = #selector(AppDelegate.togglePopover(_:))
popover.contentViewController = ViewController(nibName: "CustomViewController", bundle: nil)
}
func togglePopover(_ sender: Any){
if popover.isShown{
closePopover(sender)
}else{
showPopover(sender)
}
}
func showPopover(_ sender: Any){
if let button = statusItem.button{
popover.show(relativeTo: button.bounds, of: button, preferredEdge: NSRectEdge.minY)
}
}
func closePopover(_ sender: Any){
popover.performClose(sender)
}
func applicationWillTerminate(_ aNotification: Notification) {
// Insert code here to tear down your application
}
}
軽く説明しておくと、まずstatusItemにメニューバーでの表示方法を設定しておき、NSPopoverを取得した「popover」を作成します。
続いて、前回と同様にstatusItemでメニューバーに常駐するアプリの名前やクリックした時の処理を記述しました。
この、statusItem.actionでアイコンがクリックされた時の処理を記述しているのですが、「アイコンがクリックされたらtogglePopoverを呼びだす」ようになっています。
そのあとで、popoverで表示するCustomViewを指定しています。
今回はCustomViewContorller.xlbを作成し、ここに配置したオブジェクトが呼ばれるようにしました。
togglePopover
続いて、先ほどでてきた「togglePopover」について先に触れておきます。
こちらのコードはそのままの意味で、表示・非表示を切り替えるコードになっています。
まずpopover.isShownでポップアップウィンドウが表示されているかどうかを取得し、trueなら非表示、falseなら表示としました。
showPopover
showPopoverがウィンドウを表示するために重要なコードになっています。
statusItemがクリックされたらshowでポップアップウィンドウを表示するようにしました。
show( )では表示するウィンドウの相対的な位置などを指定しています。
closePopover
popover.performClose(sender)でポップアップしたウィンドウを閉じるようにしています。
先ほどのtogglePopoverでshowPoppoverとclosePopoverのどちらを呼び出すか判定しているというわけですね。
注意点
先ほど軽く触れましたが、今回紹介したポップアップウィンドウアプリの作り方には注意点があります。
今回使用しているNSPopoverですが、こちらは「ユーザーの環境に依存する」という問題点があります。
私の場合、メニューバーの色は「黒く」なっていますが、これは設定から変更したものでデフォルトでは白なんですよね。
NSPopoverで作成したポップアップウィンドウの色は、このメニューバーの色と同じになるのでユーザーによって白か黒か判別しなければならないようです。
完成形として一部紹介しましたが、先ほどの画像は背景に白いLabelを貼り付けて無理やり白くしていました。
では、ユーザーが白いメニューバーの時と、黒いメニューバーの時でどのように違うのか確認してください。
メニューバー白の時
メニューバー黒の時
このようにかなりイメージが変わってきてしまいました。
ユーザーの環境に依存させないためには、メニューバーの色を取得しなければならないんですかね。
ちなみにメニューバーの色は、システム環境設定 > 一般 >メニューバーとDockを暗くする
から変更することができますよ。
まとめ
今回紹介した方法で、メニューバーに常駐するアプリケーションからポップアップするウィンドウを作成することができました。
ですが、やはりユーザーの環境に依存するという難点もあるため改良が必要かもしれませんね。
【Xcode】Created byの名前を変更する方法 - クリアメモリ
より良い方法が見つかったら改めて記事にしたいと思います。
ではまた。