Timers Tech Blog

グローバルな家族アプリFammを運営するTimers inc (タイマーズ) の公式Tech Blogです。弊社のエンジニアリングを支える記事を随時公開。エンジニア絶賛採用中!→ https://timers-inc.com/engineering

macOS Catalystのメニュー対応 #hakataswift #macOSCatalyst #catalyst #macOS #Swift

f:id:fromkk:20200122190251p:plain

昨日に引き続き博多で勉強会に参加しています。
午前中は

cswift.connpass.com

に参加して、午後は

hakata-swift.connpass.com

こちらのイベントで登壇してきました。

発表資料

speakerdeck.com

macOS Catalystについて

WWDC 2019にてmacOS Catalystが発表され、iPadアプリをmacOSアプリ化することができるようになりました。
UIKitが利用できるのでこれまでiOSアプリを開発してきた技術がそのまま利用が可能になります。
少ない工数で配布できるプラットフォームが増えるのでビジネス的にもチャンスが広がるかと思います。

iPadOS向けアプリをmacOS Catalyst化する方法

XcodeのGeneralタブのDeployment InfoでMac(requires macOS 10.15)にチェックを入れるだけでmacOS向けにビルドすることができます。

f:id:fromkk:20200122190733p:plain

iOSmacOSで知っておくべき違い

macOSにあってiOSには無いものがいくつかあります。

  • タイトルバー(titleBar)
    f:id:fromkk:20200122190834p:plain
  • ツールバー(toolbar)
    f:id:fromkk:20200122190844p:plain
  • Touch Bar f:id:fromkk:20200122190850p:plain
  • メニュー(menu)
    f:id:fromkk:20200122190857p:plain

などです。 今回はメニューにフォーカスを当ててみます。

実装方法

UIResponderbuildMenu(with:)というメソッドがあるのでAppDelegateでオーバーライドします。

#if targetEnvironment(macCatalyst)
override func buildMenu(with builder: UIMenuBuilder) {
    super.buildMenu(with: builder)
    // TODO: build your menu
}
#endif

基本的にアプリを起動したタイミングか右クリックメニュー(contextMenu)が表示される際に呼ばれます。

ドキュメント: https://developer.apple.com/documentation/uikit/uiresponder/3327317-buildmenu

UIMenuBuilderにはsystemというプロパティがあり、その値をみてどのようなメニューを表示するかをハンドリングすることができます。

UIMenuSystem 定義
.main アプリ起動時に渡される。アプリ全体のメニューを構築する際に利用する。
.context 右クリックメニュー(contextMenu)が表示される際に渡される。

https://developer.apple.com/documentation/uikit/uimenusystem

UIMenu

メニューを構成するクラスです。タイトルや画像を設定することが可能です。
childrenにはUIMenuElementを継承しているクラスを入れることができるので再帰的にメニューを作っていくことが可能です。
f:id:fromkk:20200122191030p:plain

この ファイル 編集... もそれぞれが UIMenu です。

https://developer.apple.com/documentation/uikit/uimenu

UIMenu.Identifier

メニューを識別するための一意な値です。
macOSで定義されているものもありますし、独自で定義することも可能です。

UIMenuBuilder

メニューの追加・削除・入れ替えを命令するクラスです。
UIMenu.Identifierを起点として追加や入れ替えをすることが可能です。
例えば.filereplaceすればメニュー丸ごと入れ替えることができます。

https://developer.apple.com/documentation/uikit/uimenubuilder

UIAction

クロージャーの実行が可能なクラスです。
UIMenuElementを継承しているのでUIMenuchildrenに追加することができます。

UICommand

セレクターの実行が可能なクラスです。 UIActionと同じくUIMenuElementを継承しているのでUIMenuchildrenに追加することができます。

UIKeyCommand

キーボードショートカットの実現を可能にするクラスです。
前述したUICommandを継承しているのでUIMenuchildrenに追加することができます。

f:id:fromkk:20200122191106p:plain

https://developer.apple.com/documentation/uikit/uikeycommand

canPerformAction(_:withSender:)

渡されたaction: Selectorが実行可能かどうかをBoolで返すメソッドです。 メニュー自体の活性、非活性を判定します。

https://developer.apple.com/documentation/uikit/uiresponder/1621105-canperformaction

注意点

  • UIMenuSystem.mainが渡されるのはアプリの起動時のみで、しかも必要なインスタンスが生成されていない可能性が高いので事前にメニューを構築する必要があります。
    UIKeyCommandを何度も生成するのは無駄なので静的に保持しておくのが良さそうです。
  • UIMenuaction: Selectorは重複すると1つ目しか表示されないので、重複しないように設計する必要があります。同じメソッドを指定して、渡されたオブジェクトを判定して処理を分けたりする実装ができません。

まとめ

macOSアプリではメニューも大事な要素だなと感じました。
ただ、キーボードショートカット(UIKeyCommand)をメニューに入れることができるので、キーボードショートカットを実装しつつメニューを作っていくというのも良い選択肢かなと思いました。
Appleのサンプルコードもあるので参考に見てみるのをおすすめします。
macOS Catalyst化していくには避けて通れない道なので細かいメニューを作り込んでより良いmacOS Catalystアプリを作っていきましょう。

PR

この度macOS Catalystに必要な要素の実装方法をまとめた電子書籍を作成しました。
有料ですがここまでまとまった情報が日本語では見当たらなかったので個人的にはいい本が書けたと思っています。

f:id:fromkk:20200122191923j:plain

fromkk.booth.pm

積極採用中!!

子育て家族アプリFammを運営するTimers inc.では、現在エンジニアを積極採用中!
急成長中のサービスの技術の話を少しでも聞いてみたい方、スタートアップで働きたい方など、是非お気軽にご連絡ください!
採用HP: http://timers-inc.com/engineerings

Timersでは各職種を積極採用中!

急成長スタートアップで、最高のものづくりをしよう。

募集の詳細をみる