人類の多年の夢であったNSWindowのタイトルバーのカスタマイズであるが、YosemiteになってついにオフィシャルなAPIが実装された。
YosemiteではApple製のアプリケーションほとんどにおいてデザインが一新され、かつてOS Xを特徴付けていたツルッとしたテクスチャは取り払われた。そしてウインドウのタイトルバーまでもが変わった。
ウインドウのタイトルバーは、OS XにおいてGUIアプリケーションの要である。タイトルバー自体がウインドウを移動するためのノブであり、左にはウインドウを操作するための赤・黄・青のコントロールが、中央にはウインドウのタイトルが表示される。ときにはツールバーと見かけ上くっついたりするが、いずれにしてもウインドウの中心はタイトルバーである。
そのタイトルバーをカスタマイズしたい、これは全人類が生まれながらに持っている当然の欲求である。そして、しかし、Appleは長年にわたってそういったAPIを提供してこなかった。ウインドウをウインドウたらしめるタイトルバーを、心ないデベロッパーが欲望のままに毀損することを許さないというように、禁断の果実を決して手放そうとはしなかった。それがYosemiteになって、Apple製のアプリケーションでさえ、一般的なタイトルバーのルールを破壊した。いまやタイトルバーには信号機のようなコントロールを残して、タイトルの代わりにツールバーが表示されたり、あるいはウインドウのコンテンツがそのまま表示されるようになった。これはいまやAppleだけの特権ではなく、ついにAPIが提供されたのである。
タイトルを非表示にする
OS X 10.10 YosemiteからNSWindowに新しく追加されたプロパティvar titleVisibility: NSWindowTitleVisibilityを使うと、ウインドウのタイトルを非表示にできる。enum NSWindowTitleVisibilityは以下のように二つの値からなる。
enum NSWindowTitleVisibility : Int { case Visible case Hidden }
デフォルトは.Visibleであるが、ここでヘッダから.Hiddenのコメントを引用する。
The always hidden mode hides the title and moves the toolbar up into the area previously occupied by the title.
NSToolbarがある場合にはタイトルがあった場所に移動するようだ。これによって、例えばSafariやカレンダーのように、タイトルバーの高さが少し高く、信号機のようなコントロールのすぐ右にツールバーがあるようなウインドウが作れる。NSWindowにNSToolbarを設定して、あとは以下のようなコードをNSWindowControllerのfunc windowDidLoad()などに実装する。
window?.titleVisibility = .Hidden
titleVisibility = .Hiddenとしたウインドウ
タイトルバーを装飾する
OS X 10.10 YosemiteではNSViewControllerが大幅に強化され、iOSのUIViewControllerから多くの思想を受け継いだ。そして同時にNSViewControllerのサブクラスがいくつか追加された。その一つがNSTitlebarAccessoryViewControllerである。
NSTitlebarAccessoryViewControllerは、その名前が示す通り、タイトルバーを装飾するViewのControllerである。このViewControllerのviewプロパティが返すViewが、NSWindowのタイトルバーに表示される。合わせてNSWindowにも以下のようなプロパティやメソッドが追加されている。
var titlebarAccessoryViewControllers: [AnyObject] func addTitlebarAccessoryViewController(childViewController: NSTitlebarAccessoryViewController) func insertTitlebarAccessoryViewController(childViewController: NSTitlebarAccessoryViewController, atIndex index: Int) func removeTitlebarAccessoryViewControllerAtIndex(index: Int)
NSWindowは複数のNSTitlebarAccessoryViewControllerを順序付きで管理する。タイトルバーの中でどの部分に表示されるのかは、NSTitlebarAccessoryViewControllerの持つvar layoutAttribute: NSLayoutAttributeというプロパティで決定される。ただし現在の所NSLayoutAttributeのうち有効な値は.Bottomと.Rightのみであることがヘッダに書かれている。もちろんそれぞれに対応する位置は、タイトルバーの下と右である。
実際に表示するには以下のようなコードを、例えばNSWindowControllerのfunc windowDidLoad()に実装する。NSTitlebarAccessoryViewControllerのインスタンスはStoryboardから生成している。
let accessory = storyboard?.instantiateControllerWithIdentifier("TitlebarAccessory") as NSTitlebarAccessoryViewController accessory.layoutAttribute = .Right window?.addTitlebarAccessoryViewController(accessory)
layoutAttribute = .BottomのNSTitlebarAccessoryViewControllerを設定したウインドウ
layoutAttribute = .RightのNSTitlebarAccessoryViewControllerを設定したウインドウ
コンテンツをタイトルバーの領域まで拡げる
タイトルバーの位置までウインドウのコンテンツを表示するために、新たにvar titlebarAppearsTransparent: Boolプロパティと、NSFullSizeContentViewWindowMask定数が用意された。
titlebarAppearsTransparentはタイトルバーの背景を透明にするかどうかを表す。NSFullSizeContentViewWindowMaskは、NSWindowのvar styleMask: Intプロパティに利用する定数で、タイトルバーの領域までをコンテンツの領域とすることを表現するものである。
NSFullSizeContentViewWindowMaskとNSScrollViewの組み合わせによって、タイトルバーの下にコンテンツが透けるような表現が可能になる。またNSFullSizeContentViewWindowMaskを設定した上でtitlebarAppearsTransparentを真にすると、信号のようなコントロールだけのウインドウが作れるのだ。
window?.titleVisibility = .Hidden window?.styleMask |= NSFullSizeContentViewWindowMask window?.titlebarAppearsTransparent = true
NSSplitViewのコンテンツを表示させるようにしたウインドウ
伝統的手法
有史以来、NSWindowのタイトルバーをカスタマイズすると言えば大きく二つの方法があり、ひとつはウインドウのコントロールまで完全に自作して自由に表示する方法、そしてもうひとつはwindow.contentView.superviewという風にNSWindowの実装に依存してビューの階層を辿る方法である。現実的には主に後者が利用されることが多かったのではないだろうか。(NSThemeFrameなどで検索するとそういった方法を指し示すページが今も見つかるだろう。)
しかしOS X 10.10 Yosemiteでは、このビューの階層を辿る方法を使っていると"NSWindow warning: adding an unknown subview:"というログが出力されるようになり、代わりにオフィシャルな方法が提供されることになった。このことはAppKitのリリースノートに記載されている。
まとめ
ここまでで、OS X 10.10 Yosemiteから追加されたAPIによって、柔軟にタイトルバーをカスタマイズできることがわかった。これらはもちろん組み合わせることもできる。例えばSafariでは、titlebarAppearsTransparent = trueとした上でlayoutAttribute = .BottomのNSTitlebarAccessoryViewControllerを設定しているかもしれない。
titlebarAppearsTransparent = trueかつlayoutAttribute = .BottomのNSTitlebarAccessoryViewControllerを設定したウインドウ
また昨今噂されるUXKitでは、UXNavigationControllerなどUIKit由来の機能が存在するらしい。これらのNSWindowの新しいAPIを使って、例えばUINavigationBar相当の機能をタイトルバーに押し込めることもできるのではないだろうか。
まだ見ぬOS X 10.11への期待を膨らませつつ、読者諸氏もNSWindowのタイトルバーをカスタマイズしてみてほしい。こちらからは以上だ。
- 作者: 荻原剛志
- 出版社/メーカー: SBクリエイティブ
- 発売日: 2014/12/10
- メディア: 大型本
- この商品を含むブログ (2件) を見る