見出し画像

Touch Bar on Catalyst #potatotips #catalyst

 4/27(月)の20時からオンラインで開催された[Online] potatotips #69 iOS/Android開発Tips共有会に登壇しました。

このイベントは僕がTimersに出社してた頃に「4月のpotatotipsが無くなったんだけどオンラインにしてうちでできないかな?」と社内に打診したことがきっかけだったりしたので謎の責任感でとりあえず登壇枠で申し込んでおきました。主催、MCをしてくれた@akatsukiさんありがとうございました。内容については以前書いた本の内容を一部切り出して発表した感じです。

登壇内容

 Catalyst自体はWWDC 2018で発表されたmacOS MojaveでApple製のアプリケーションの一部にUIKitが利用され、Apple社内でテスト的に利用が開始されました。それらのアプリケーションとはNews、株価、ボイスメモ、ホームの4です。開発者向けには2019年のリリースとなることがアナウンスされました。そして翌年のWWDC 2019にてProject Catalystが発表され、macO向けのアプリケーションの開発にUIKitが利用できることが発表されました。もちろんiOSとmacOSには様々な違いがあるのですがそれらも吸収されています。(メニューバーで動作するアプリケーションなど非対応の機能もまだまだあります)それでも同じコードベースのアプリケーションがiPhone、iPad、Macで動作させることが可能になりました。その中でも今回はTouch Barの実装方法について調べたので発表します。

Touch Barとは

 Touch Barは2016年に発売されたMacbook Proから搭載されたキーボードの奥側に配置されるディスプレイつきのコントロールバーです。発売当時からEscキーとファンクションキーが Touch Barに内包されてしまい賛否両論ありました。しかし、2019年11月に発売されたMacbook Pro 16インチではEscキーが復帰したことで待ち望んでいた人は大歓喜となりました。
 iOS 13のCatalystで利用可能なボタンの種類がこちらです。

画像1

実装方法

 まず、タッチバー自体の種類を判別するための識別値を定義します。NSTouchBar.CustomizationIdentifierを拡張して利用するのが良いかと思います。

extension NSTouchBar.CustomizationIdentifier {
   static let myTouchBar = NSTouchBar.CustomizationIdentifier(
       "me.fromkk.CatalystSampler.MyTouchBar"
   )
}

次にタッチバーに表示する項目の識別値を定義します。こちらもNSTouchBarItem.Identifierを拡張して利用するのが良いかと思います。

extension NSTouchBarItem.Identifier {
   static let prev = NSTouchBarItem.Identifier(
       "me.fromkk.CatalystSampler.prev"
   )
   static let next = NSTouchBarItem.Identifier(
       "me.fromkk.CatalystSampler.next"
   )
}

Catalystの場合にUIResponderにmakeTouchBarというメソッドが増えているのでこちらを実装します。

#if targetEnvironment(macCatalyst)
override func makeTouchBar() -> NSTouchBar? {
   let touchBar = NSTouchBar()
   touchBar.customizationIdentifier = .myTouchBar
   touchBar.defaultItemIdentifiers = [.prev, .next, .otherItemsProxy]
   touchBar.customizationAllowedItemIdentifiers = [
       .prev, .next
   ]
   touchBar.delegate = self
   return touchBar
}
#endif

NSTouchBarクラスに色々なプロパティがありますが、最低限defaultItemIdentifiersとdelegateを実装すれば動くかと思います。

画像2

 タッチバーにはユーザーが表示する項目や並び順を変更することができるカスタマイズ機能があります。カスタマイズ機能へは「表示」メニューから「Touch Barをカスタマイズ…」を選択することでアクセス可能です。これらの項目はcustomizationAllowedItemIdentifiersやcustomizationRequiredItemIdentifiersを指定することでコントロール可能です。
 最後にNSTouchBarDelegateプロトコルを適合して実装します。

func touchBar(_ touchBar: NSTouchBar, makeItemForIdentifier identifier: NSTouchBarItem.Identifier) -> NSTouchBarItem?

ここで先ほど設定したidentifierが渡されてくるのでハンドリングしてNSTouchBarItemのサブクラスを生成して返します。これでタッチバーが表示されます。
 通常一つの画面に複数のUIResponderが存在するのでmakeTouchBarメソッドが複数実装される可能性があります。そういう場合には表示するための優先度が決まっています。また、makeTouchBarメソッドが実装されていなくてもUIResponderを見つけた場合には更に検索を実施します。これはAppKitで定義されているものですが、おそらくCatalystでもほとんど変わらないのでは無いかと思います。

画像3

注意点

 まず、SwiftUI(UIViewControllerRepresentableやUIViewRepresentableでラップした場合)ではうまく表示されませんでした。但し、windowSceneのtouchBarプロパティに無理やりNSTouchBarのインスタンスを渡せば表示することができました。SwiftUIを利用したい場合は、Catalystでは無く普通にmacOSネイティブアプリを開発した方がいいのかもしれません。(iOSには無いtouchBarメソッドがmacでは利用可能)
 また、スライダーを表現するNSSliderTouchBarItemから値を取得するプロパティやメソッドがありません。value(forKey:) メソッドで取得することができますが、これで合ってる?という感じです。(プライベートAPIの可能性がありリジェクトリスクがあります)

まとめ

 Catalyst自体まだまだ発展途上の印象がありますが、その中でもTouch Barはニッチなのか対応に遅れがある印象を抱きました。対応されているNSTouchBarItemの種類もまだ少ないし値がちゃんと取れなかったりするのでこの辺りは今後に期待という感じです。それでもTouch BarはmacOSならではの要素の一つなのでCatalyst対応する際には忘れずに実装したいですね。ちなみに先日リリースしたPity# Typeも一部分の画面でTouch Bar対応しています。良かったら見てみてください。CatalystでTouch Bar以外の実装どうするの?と思った人は良かったら電子書籍の方にも情報をまとめているのでそちらも見ていただけると嬉しいです。


この記事が気に入ったらサポートをしてみませんか?