LoginSignup
1
3

More than 3 years have passed since last update.

Swift:マルチディスプレイでもNSStatusBarButtonのアイコンの色を保つ

Last updated at Posted at 2020-03-24

メニューバーアプリ開発のTipsです.

マルチディスプレイの状態でMacのメニューバーを眺めていると,非アクティブなディスプレイでは基本的にアイコンが色を失ってグレーアウトするのですが,たまにそのお約束を無視している子がいます.

スクリーンショット 2020-03-24 15.07.52.png

Siriのアイコンとか,LINEのアイコンとかです.

これがどうやってるのか気になって調べたり検証したところ,やり方そのものは簡単なのですが,情報が全然なかったので記しておきます.

ポイント

  • NSStatusBarButton.imageにアイコンを設定するだけだとグレーアウトする
  • NSStatusBarButtonにNSViewをaddSubviewしてその中でdrawするとグレーアウトしない
  • NSStatusBarButton.imageにアイコンを設定しないとボタンの大きさや位置が定まらない
  • NSStatusItem.lengthで幅を設定することもできるけれどあまり賢い方法ではない

解決法

  1. NSStatusBarButton.imageにアイコンサイズと同じサイズの透明なNSImageを設定する
  2. 独自NSViewを用意して,アイコンNSImageとNSStatusBarButtonの大きさを渡す
  3. NSStatusBarButtonに独自NSViewをaddSubViewしてマージンを計算して配置する

サンプルソース

AppDelegate
import Cocoa

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {

    let statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
    var button: NSStatusBarButton!

    func applicationDidFinishLaunching(_ aNotification: Notification) {
        button = statusItem.button
        button.image = NSImage(size: NSSize(width: 18.0, height: 18.0))
        let icon = NSImage(imageLiteralResourceName: "SampleIcon")
        let iconView = IconView(icon, button.bounds.size)
        button.addSubview(iconView)
    }

    func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
        return true
    }

}
IconView
import Cocoa

class IconView: NSView {

    var icon: NSImage?

    init(_ icon: NSImage, _ size: CGSize) {
        super.init(frame: NSRect(x: 0.5 * (size.width - 18.0),
                                 y: 0.5 * (size.height - 18.0),
                                 width: 18.0, height: 18.0))
        self.icon = icon
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func draw(_ dirtyRect: NSRect) {
        icon?.draw(in: NSRect(x: 0.0, y: 0.0, width: 18.0, height: 18.0))
    }

}

サンプルの結果

スクリーンショット 2020-03-24 15.57.04.png

ちゃんと非アクティブなディスプレイでも色を保っています.

ちなみに,メニューバーの高さ上限は22ポイントですが,22ポイントのアイコンだと窮屈なので,高さは18ポイントが良いです.横幅には制限がないです.(18ポイントということは,最近のMacはRetinaディスプレイなので綺麗に表示するなら2倍の36ピクセルが必要です.)

蛇足

NSStatusBarButton.titleに顔文字を指定しても色がついたままになります(色褪せますが).

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