[Xcode 8.1] サンプルコードからTouchBarのAPIを理解する#2 NSTouchBar Catalogの初期画面でやっていること
本記事の目標:ButtonViewController.swiftでやっていることを理解する
こんにちは!モバイルアプリサービス部の加藤潤です。
前回に引き続きNSTouchBar Catalogを理解していきます。
今回はサンプルアプリを起動すると最初に表示される画面(ButtonViewController.swift
)で何をやっているかを見ていきたいと思います。
(※実は前回の記事の実行結果に載せた画面キャプチャはWindowController.swift
で何をやっているかを理解しやすくするためにMasterViewController.swift
の処理の大半をコメントアウトして実行した結果でした。)
実行結果
先にアプリとタッチバー、カスタマイズパレットの実行結果を載せておきます。
アプリとタッチバー
「Size Constraint」にチェックを入れると「Button 3」と書かれたボタンの幅が大きくなります。 また、「Custom Button Color」にチェックを入れると3つのボタンの色が黄色になります。ボタンのタイトルも変化しています。
カスタマイズパレット
「Catalog」と書かれたアイテムとその隣のスペースアイテムは削除したり、配置の入れ替えができますが、3つのボタンについてはそれができない作りになっています。
3つのボタンを持つタッチバーはStoryboardで定義されている
3つのボタンを持つタッチバーは以下のようにButtonViewController.storyboard
で定義されています。
コードを読み解く
ButtonViewController.swift
ButtonViewController.storyboard
の中でInitial Controllerとして定義されている、NSViewController
のサブクラスであるButtonViewController
クラスのソースコードは以下のようになっています。
import Cocoa class ButtonViewController: NSViewController { @IBOutlet weak var sizeConstraint: NSButton! @IBOutlet weak var useCustomColor: NSButton! @IBOutlet weak var button3: NSButton! lazy var button3Constraints: [NSLayoutConstraint] = { return NSLayoutConstraint.constraints(withVisualFormat: "H:[button3(200)]", options: [], metrics: nil, views: ["button3": self.button3!]) }() // MARK: - Action Functions @IBAction func customize(_ sender: AnyObject) { guard let touchBar = self.touchBar else { return } for itemIdentifier in touchBar.itemIdentifiers { guard let item = touchBar.item(forIdentifier: itemIdentifier) as? NSCustomTouchBarItem, let button = item.view as? NSButton else {continue} let textRange = NSRange(location: 0, length: button.title.characters.count) let titleColor = useCustomColor.state == NSOnState ? NSColor.black : NSColor.white let newTitle = NSMutableAttributedString(string: button.title) newTitle.addAttribute(NSForegroundColorAttributeName, value: titleColor, range: textRange) newTitle.addAttribute(NSFontAttributeName, value: button.font!, range: textRange) newTitle.setAlignment(.center, range: textRange) button.attributedTitle = newTitle button.bezelColor = useCustomColor.state == NSOnState ? NSColor.yellow : nil } if sizeConstraint.state == NSOnState { NSLayoutConstraint.activate(button3Constraints) } else { NSLayoutConstraint.deactivate(button3Constraints) } } @IBAction func buttonAction(_ sender: AnyObject) { print("\(#function): button with title \"\((sender as! NSButton).title)\" is tapped!") } }
20〜21行目
20行目から始まるアクションメソッドは、「Size Constraint」、「Custom Button Color」のどちらのチェック状態が変化しても呼ばれます。
このメソッド内の処理で特筆すべきところは、self.touchBar
でstoryboardで定義したタッチバーのインスタンスが取得できるところでしょうか。このプロパティの定義はNSResponder
にありますが、NSViewController
がNSResponder
を継承していて、かつstoryboard上でタッチバーを階層的にButtonViewController
の中に配置しているためにこのプロパティで取得できているのでしょう。
23行目
itemIdentifiers
プロパティでバー内のアイテムIDを取得してループ処理をしています。このプロパティは読み取り専用プロパティで、ユーザーによってバーがカスタマイズされていない場合はdefaultItemIdentifiers
と同じアイテムIDの配列を返します。
25〜26行目
touchBar.item(forIdentifier: itemIdentifier)
の部分でアイテムIDを指定してNSTouchBarItem
を取得し、更に今回はアイテム内のビューとしてNSButton
を配置しているため、NSCustomTouchBarItem
にキャストしています。
NSCustomTouchBarItem
にキャストすることで、view
プロパティを通じてNSButton
を取得しています。
28〜45行目
ボタンのattributedTitle
やbezelColor
を設定しています。bezelColor
は「Custom Button Color」のチェックありの場合はyellow、チェックなしの場合はnilを設定しています。
また、「Size Constraint」のチェックありの場合はbutton3Constraints
の制約を有効に、チェックなしの場合は無効にしていますね。
button3Constraints
はVFL(Visual Format Language)で定義されたAutoLayoutの制約です。
制約の内容は「button3
の横幅を200
にする」です。VFLについてはこちらをご覧ください。
おわりに
今回はButtonViewController.swift
のコードから、storyboardで定義されたタッチバーをコードから取得してカスタマイズする方法を学びました。
まだまだ奥が深いタッチバーです。