iOSエンジニアの西方です。
iPhone SEが発売されました。 個人的には大きな画面のiPhone 6 Plusシリーズが好きなので、今さら4インチに興味はなかったのですが、片手に収まるこのサイズに魅力を感じている方も少なくないでしょう。
開発者としては複雑な気分です。 そろそろ4インチユーザーが減ってくるかなと願っていた矢先の4インチデバイス再来。まだまだ4インチのサポートを切ることはできませんね。
前置きが長くなりましたが、複数の画面サイズに対応する際、なくてはならないのがAuto Layoutです。 iPhoneだけで4通りのサイズ展開となっている今、Auto Layoutなしで画面実装を進めることは難しいでしょう。
今回の投稿では、Auto Layoutの中でも少し特殊な「固有サイズの優先度」について、その意味と使い方を説明します。
固有サイズを使う
Auto Layoutでビューのサイズを指定するためには、幅や高さに関する制約を利用します。 しかし、コンテンツに合わせてビューのサイズを動的に変化させたいケースもあります。 このとき使うのが固有サイズです。
固有サイズとは
「固有サイズ」とは、ビューのコンテンツにマッチしたサイズのことです。英語では、「Intrinsic Content Size」と表記されています。UILabelを例に挙げると、コンテンツが『Money』であるラベルと、『Money Forward』であるラベルとでは、前者の固有サイズの方が小さくなります。
下図は、Storyboard上でそれぞれのラベルを固有サイズで表示した様子です。
システムは、サイズに関する制約が設定されていないビューがあると、固有サイズを元にレイアウトします。
ビューの配置に関する制約を設定する
ここからは実際に、画面上に配置した2つのUILabelに制約を設定しながら解説します。
設定するのは、次の4つの制約です。
- 水平方向
- ラベルとラベルの間隔を20に固定する
- 左側のラベルと親ビューの左端との間隔を20に固定する
- 右側のラベルと親ビューの右端との間隔を20以上にする
- 垂直方向
- 垂直方向の位置を親ビューの中央に揃える
この状態で、Xcodeのプレビュー表示を使い各デバイスでのレイアウトを見てみます。
この状態では問題はありません。
固有サイズと他の制約との競合
次に、左のラベルに『Money Money Money Money Money』、右のラベルに『Forward Forward Forward Forward Forward』と設定してみます。
制約に関するエラーが発生した上に、4インチ上からはForwardラベルが消えてしまいます。 (制約が競合しているため、実際の見え方は異なる可能性があります)
エラーには、「Compression Resistance Priority」と「Hugging Priority」という2種類の優先度を制御するようにアドバイスが出ています。
固有サイズを含めた制約全体に不整合が生じ、ビューが正しくレイアウトできない状態です。
各ラベルの矩形をコンテンツに合わせようとすると、ラベルが親ビューからはみ出してしまい、他の制約を満たすことができません。
このままでは、システムがビューのレイアウトを決定することができません。そこで必要となってくるのが、固有サイズの優先度です。
固有サイズの優先度
固有サイズと他の制約とが競合したときに、どの値を優先するか指定しなくてはなりません。そのために用いるのが固有サイズの優先度です。
優先度の種類
固有サイズには次の2通りの優先度があります。
- Content Compression Registance Priority
- コンテンツのつぶれにくさ
- コンテンツが大きすぎるときに、ビューの矩形を広げてコンテンツをつぶさないようにする
- Content Hugging Priority
- 余白のできにくさ
- コンテンツが小さすぎるときに、ビューの矩形を狭めて余白を作らないようにする
優先度が高ければ高いほど、システムは、ビューの矩形をコンテンツのサイズに近づけようとします。
コンテンツが大きすぎるときの制御
百聞は一見に如かず。実際に優先度を設定してみます。
いま問題になっているのは、コンテンツが大きすぎることです。したがって、この問題を解決するためには、Compression Registance Priority の設定が必要です。
右側のラベル表示の優先度を高くしましょう(右側のラベルでコンテンツがつぶれないようにする)。右側のラベルのCompression Registance Priorityを751に変更します。
設定は、ユーティリティエリア(Xcodeの右エリア)にあるSize Inspectorで行います(下図)。
プレビューで確認すると、今度は左側のラベルが完全に押しつぶされて、非表示になってしまいます。さすがにこれでは困るので、左側のラベルには最低幅を設定します。幅が65以上となるように制約を追加しましょう(下図)。
もう一度プレビューで確認すると、どのデバイスでも意図通り表示されています。
コンテンツが小さすぎるときの制御
次に、左側のラベルを『M』右側のラベルを『F』に書き替えてみましょう。再び優先度に関するエラーが表示されてしまいます。
今度はコンテンツが小さすぎることが問題なので、制御すべき優先度はContent Hugging Priorityです。
左側のラベルには極力余白ができないようにしましょう(右側のラベルには余白を許容する)。そのために、左側のラベルのContent Hugging Priorityを252に変更します。
ここで注意したいのが、左側のラベルにはすでに、幅が65以上になるように制約が設定されていることです。この制約の優先度はデフォルトの1000であり、Content Hugging Priorityより大きいため、「幅65以上」という制約が最優先されます。
これで、コンテンツサイズに依らず制約の不整合が発生しなくなりました。
ラベル使用例
例として、左側のラベルに『Money Forward』、右側のラベルに『お金を前へ。人生をもっと前へ。』と設定すると、次のように表示されます。
- 4インチ
- 左ラベルの最低幅が65となる(Width Priority:最高)
- 右ラベルのコンテンツをできる限り表示する(Compression Registance Priority:高)
- 左ラベルのコンテンツをできる限り表示する(Compression Registance Priority:低)
- 4.7インチ
- 右ラベルのコンテンツ全体を表示する(Compression Registance Priority:高)
- 左ラベルのコンテンツをできる限り表示する(Compression Registance Priority:低)
- 5.5インチ
- 左ラベルのコンテンツを余白なしで表示する(Hugging Priority:高)
- 右ラベルに余白をつけて表示する(Hugging Priority:低)
まとめ
Auto Layoutでは、複数のビューに固有サイズを適用すると、コンテンツのサイズによってはレイアウトが一意に決まりません。この問題を解決するために用意されているのが、固有サイズの優先度です。
固有サイズの優先度と、幅または高さに関する制約の優先度をうまく制御することで、希望通りのレイアウトが実現できます。幅や高さの制約には、固定値だけでなく最大値または最小値を設定してみるのもよいでしょう。
特に、ラベルに表示する内容が動的に変化するケースでは、十分に注意して実装とテストを行わないと、ユーザーの環境で予期せぬことが起きているかもしれません。
Auto Layoutを賢く使って、デバイスサイズやコンテンツの変化にも強いレイアウトを実現したいものです。
最後に
マネーフォワードでは、デバイスサイズの多様化に負けない強い心を持ったアプリエンジニアを募集しています。 ご応募お待ちしています。
【採用サイト】 ■マネーフォワード採用サイト ■Wantedly | マネーフォワード
【プロダクト一覧】 ■家計簿アプリ・クラウド家計簿ソフト『マネーフォワード』 ■家計簿アプリ・クラウド家計簿ソフト『マネーフォワード』 iPhone,iPad ■家計簿アプリ・クラウド家計簿ソフト『マネーフォワード』 Android ■クラウド型会計ソフト『MFクラウド会計』 ■クラウド型請求書管理ソフト『MFクラウド請求書』 ■クラウド型給与計算ソフト『MFクラウド給与』 ■経費精算システム『MFクラウド経費』 ■消込ソフト・システム『MFクラウド消込』 ■マイナンバー対応『MFクラウドマイナンバー』 ■創業支援トータルサービス『MFクラウド創業支援サービス』 ■お金に関する正しい知識やお得な情報を発信するウェブメディア『マネトク!』