iOS Size Classesを利用してユニバーサル対応を行った話
山口 恭兵
こんにちは。AirレジのiOSアプリ開発を担当している山口です。
Airレジは昨年5月に行ったリニューアルに伴い、ユニバーサル対応を行いました。それまではiPhone/iPadで別アプリとして管理していましたが、ユニバーサル対応によりメンテナンスコストを下げることができました。
しかし、開発当初はSize Classesについての理解が浅いままユニバーサル対応を進めてしまい、レイアウト作成中に手戻りが発生したり、UIの共通化が上手くいかず分岐が複雑になってしまうなどの問題が発生していました。そこで、今回はSize Classesの概要とポイントについて書いてみました。
これからユニバーサル対応を始める方の参考になれば幸いです。
Size Classes
iOS8以降、多様化する画面サイズを抽象化して扱うための概念としてSize Classesが登場しました。様々なデバイスや向きに対応したAdaptive UIを実現する上で重要な概念となっています。AirレジはiPhone縦向き/iPad横向きの2パターンのみ対応していますが、メディア系アプリなどはAdaptive UIに対応することでより優れたユーザ体験を提供することができます。
Size Classesでは画面のwidth・heightそれぞれに対して、Compact・Regularサイズが定義されています。何十パターンにも及ぶデバイスサイズ、向きの違いを下図のように4パターンで表すことができます。
WWDC2016 Making Apps Adaptiveより
Interface BuilderによるSize Classesの利用
Xcode8からSize Classesの使い勝手が大きく改良されました。ここでは、Interface Builderで実際にどのようにSize Classesを利用するかを書いていきます。
動作確認環境は、執筆時点で最新のXcode8.2.1となっています。
Device configuration pane
Interface Builder下部にdevice configuration paneが追加されました。ここでは、デバイス・向きを選択することで、現在設定されている設定や制約に応じた表示を確認することができます。Xcode7ではCompact・Regularなどサイズベースで選択していましたが、デバイスベースで選択できるようになったため、より理解しやすくなっています。
各Size Class共通のレイアウト設定
Size Classesを利用したレイアウトを作成する上で、まずはベースとなるレイアウトを作成していきます。device configuration paneから、アプリケーションのメインとなるデバイス・向きを選択して作成していくとよいでしょう。Airレジの場合はiPadの横向きがメインなので、それをベースとしています。
この状態で設定したViewやそのプロパティ・制約については、どのサイズにおいても適用されます(Xcode7でのwidth:Any・height:Any)。
Size Class別のレイアウト設定
上記の例で、iPhone縦画面のようなwCompact・hRegularサイズのときだけ、青と赤のViewを縦並びにしたい場合などがあるかと思います。
device configuration paneから対象のデバイス(サイズ)を選択した状態で、Attributes Inspectorの「+」→「Add Variation」をクリックすることでwidth:Compact・height:Regularサイズの場合のみ縦並びにすることができます。この他にも、下記のような様々なプロパティに対してサイズ毎の設定を行うことが可能です。
- フォントサイズ
- 色
- View自体の表示・非表示(※isHiddenプロパティとは別)
- AutoLayoutの制約 など
また、特定サイズだけ新たにViewや制約を追加したい場合は、device configuration paneの「Vary for Traits」をクリックした上でViewや制約を設定することで該当サイズの場合は有効、他のサイズの場合は無効とすることができます。
Size Classes利用時のポイント
Airレジでユニバーサル対応を行った際に得られたポイントや注意点をご紹介します。
デザイナーとSize Classesについて認識を合わせる
Size Classesについて深く理解しているデザイナーの方はまだまだ少ないかと思います。そうした場合、iPhone/iPadでデバイス別のレイアウト指示書などが納品されてくるかと思います。しかし、Size Classesの概念ではデバイスによる分類ができないため別途UIUserInterfaceIdiom
を見てレイアウトを変えるなど条件が増えてしまったり、レイアウト自体を再検討する必要がでてきます。
事前にデザイナーとSize ClassesやAutoLayoutの概念について認識を合わせてから、レイアウト作成にとりかかるようにすることが重要だと感じました。
UIModalPresentationStyleの扱いに注意する
ViewControllerをモーダル表示する際のスタイルによって、ViewControllerに適用されるSize Classが異なるため注意が必要です。iPadの場合、UIModalPresentationStyle.formSheet
ではwidth:Compact・height:Regular、UIModalPresentationStyle.pageSheet
ではwidth:Regular・height:Regularとなります。
冒頭で述べたように、表示する画面サイズによってSize Classが定義されるため当然といえば当然ですが、同一デバイスであっても状況によって適用されるSize Classが異なってくるという認識をもつことが重要です。私は当初、iPad = width:Regular・height:Regularといった認識をしていたため、UIModalPresentationStyle.formSheet
で表示した際に想定通りのレイアウトにならず痛い思いをしました。
Interface BuilderでのInstalledの扱いに注意する
Size Classに応じてViewの表示・非表示を切り替えるInstalledの設定ですが、対象のViewが表示されていない場合の状態は下記のようになっています。Viewの表示状態によって処理を分ける場合などは注意が必要です。
- IBOutletで接続しているインスタンス自体は存在する
isHidden
プロパティがtrue
になるわけではない- View階層から削除されるため、
superview == nil
となる
おわりに
今後、iOSアプリを作成する上でAdaptive UIという考え方が重要になってくるかと思います。従来のようにデバイス種別や向きでレイアウトを区別するのではなく、表示される画面サイズによってレイアウトを区別するという認識をチーム全体で持つことが重要だと思いました。