端末の画面サイズごとにレイアウトを変更できる"Vary for Traits"の使い方

#はじめに
いきなりですが、Xcodeの**Vary for Traits** という機能をご存知ですか？

<img width="429" alt="スクリーンショット 2019-12-21 13 05 31" src="https://user-images.githubusercontent.com/37994872/71302779-c3aa5800-23f2-11ea-8c17-c60440e73a4c.png">

InterfaceBuilderの下のバーにある、グレーのボタンで使うことができます。

一体どういうことができる機能かというと、コードの記述なしに端末の画面サイズや回転状況に応じて、AutoLayoutの制約を付け替えたり、制約の数値を変更、色の変更などのレイアウト周りの設定の変更を行うことができます。

それによってiPhoneとiPad間でのレイアウト崩れを防いだり、画面回転時に全く違うレイアウトを表示するといった活用ができます。

今回は、そんなVary for Traits機能を使用する方法を紹介します。

#画面サイズの定義を知る
Vary for Traits機能は画面サイズの定義ごとにレイアウト設定を変更するので、使用する前に、まずは画面サイズの定義を知ることが必要不可欠です。
画面サイズの定義は、横幅と縦幅の`w(Width)`と`h(Height)`、サイズの大小の`R(Regular)`と`C(Compact)`、の二つの概念の組み合わせでできています。

以下の画像はInterfaceBuilderでiPhone 11 Pro Maxの縦向き状態でViewを表示した際のスクリーンショットです。
左下に、`View as: iPhone 11 Pro MAX(wC hR)`と書かれています。

![スクリーンショット 2019-12-20 17 18 38](https://user-images.githubusercontent.com/37994872/71240639-074a8680-234d-11ea-8723-89817545374d.png)

iPhone 11 Pro Maxを縦向きにしている状態の画面サイズは`wC  hR`、つまり横幅が小さく、縦幅が大きい端末と定義されていることがわかります。

ちなみに、それぞれの端末がどのように定義されているかは以下の表に起こしたので、参考にしてください

|  | w | h |
| ---- | :--: | :--: |
|iPhone(縦)|C|R|
|4s・SE・8・11 Pro(横)|C|C|
|8Plus・11・11 Pro MAX(横)|R|C|
|iPad(縦横両方)|R|R|

縦向きのiPhoneの`wC hR`、横向きのiPhoneが`hC`、iPadの`wR hR`などはよく使うので覚えておくと良いでしょう。

#Vary for Traitsを使う
それぞれの端末のサイズ定義がわかったところで実際にVary for Traits機能を使用してみましょう。

##準備
例として、まずは画面の中心に横幅300×高さ400の制約を設定したViewを配置します。

<img width="309" alt="スクリーンショット 2019-12-21 12 56 14" src="https://user-images.githubusercontent.com/37994872/71302665-6366e680-23f1-11ea-81d3-16099a70a92c.png">

その状態で画面を横向きに変更すると、画面自体の高さが400以下になってしまうので、画面から高さ400の制約を設定したViewが見切れて表示されてしまいます。

<img width="430" alt="スクリーンショット 2019-12-21 13 21 28" src="https://user-images.githubusercontent.com/37994872/71302936-d160dd00-23f4-11ea-9a20-d5678bb02f9e.png">

この状態からVary for Traits機能を使って、画面が横になった場合にレイアウトを変えていきます。

##定義したい画面サイズを選択する
早速、Vary for Traitsのボタンをクリックすると、以下の画像の吹き出しが現れます。
WidthとHeightのチェックボックスは、現在表示しているInterfaceBuilderで選択されている画面のサイズ定義で個別に設定したいものにチェックを入れます。

<img width="244" alt="スクリーンショット 2019-12-21 13 25 14" src="https://user-images.githubusercontent.com/37994872/71303092-77154b80-23f7-11ea-9e89-90cb25f95933.png">

現在表示している画面はiPhone 11 Pro Maxの横向きなので、画面サイズの定義は`wR hC`です。

両方にチェックを入れると`wR hC`の組み合わせのである、`8Plus・11・11 Pro MAXの横向き`で表示した際に、有効になるレイアウトを設定できます。

Widthのみにチェックを入れた場合は`wR`が指定されている、`横向きの8Plus・11・11 Pro MAXとiPad`で表示した際に、有効になるレイアウトを設定できます。

Heightのみにチェックを入れた場合は`hC`が指定されている、`横向き状態のiPhone`で表示した際に、有効になるレイアウトを設定できます。

今回の場合、iPhoneの横向きで表示した際にViewが画面外にはみ出してしまうので、Heightの方にのみチェックを入れます。

<img width="264" alt="スクリーンショット 2019-12-21 13 25 31" src="https://user-images.githubusercontent.com/37994872/71302963-606df500-23f5-11ea-9635-686255612de4.png">

これで`hC`の画面サイズのみで有効になるレイアウトが設定できる状態になりました。

##特定の画面サイズでレイアウトを設定する
###1.制約の数値を変更する
まずは、Viewの高さの制約を変更してみましょう。
高さの制約の設定を確認すると以下のようになっています。

<img width="257" alt="スクリーンショット 2019-12-21 13 46 11" src="https://user-images.githubusercontent.com/37994872/71303173-484ba500-23f8-11ea-9f7e-612e0d820cd6.png">

この中の`Constant`の左側の＋をクリックすると、以下の画像の吹き出しが出ます。
そのまま`Add Variation`をクリックします。

<img width="472" alt="スクリーンショット 2019-12-21 14 23 47" src="https://user-images.githubusercontent.com/37994872/71303552-b8a8f500-23fd-11ea-97d8-3b4c5d23e299.png">

そうするとConstantの入力欄の下に`hC`の欄が追加されるので、そこに250を設定してみます。

<img width="255" alt="スクリーンショット 2019-12-21 14 27 11" src="https://user-images.githubusercontent.com/37994872/71303609-7a600580-23fe-11ea-9bf8-cf23482a8462.png">

そうすると、Viewの高さがちゃんと画面内に収まるようになりました。

<img width="395" alt="スクリーンショット 2019-12-21 14 45 45" src="https://user-images.githubusercontent.com/37994872/71303761-96fd3d00-2400-11ea-8a93-0539ca5ae0bd.png">

`hC`での数値を変更したので、もちろん縦向きに変更しても影響はありません。

<img width="216" alt="スクリーンショット 2019-12-21 14 50 15" src="https://user-images.githubusercontent.com/37994872/71303808-37ebf800-2401-11ea-8506-65963a91dc5b.png">

###2.制約の有効・無効を設定する
次は横向きの時には、赤いViewの中央揃えではなく、左上に配置するように設定してみましょう。

先ほどのように、`View.Center Y`の制約を選択し、今度は`Installed`の横の＋をクリックして、吹き出しの`Add Variation`をクリックします。

<img width="464" alt="スクリーンショット 2019-12-21 14 59 04" src="https://user-images.githubusercontent.com/37994872/71303907-7b933180-2402-11ea-8459-cf1300a02308.png">

すると、Installedの下に`hC`用のチェックボックスが追加されるので、チェックを外すと、制約が無効化されます。

<img width="256" alt="スクリーンショット 2019-12-21 15 00 20" src="https://user-images.githubusercontent.com/37994872/71303939-a1b8d180-2402-11ea-81c1-813101c05b24.png">

同じように`View.Center X`の制約も`hC`のInstalledのチェックボックスを追加して、チェックを外しておきましょう。

<img width="255" alt="スクリーンショット 2019-12-21 15 02 15" src="https://user-images.githubusercontent.com/37994872/71303958-e5abd680-2402-11ea-99ad-49f0ed257b70.png">

すると、以下の画像のような状態になるので、ここから新たに制約を設定していきましょう。

<img width="345" alt="スクリーンショット 2019-12-21 15 04 14" src="https://user-images.githubusercontent.com/37994872/71303977-2efc2600-2403-11ea-9e03-58c17d2af238.png">

今回は左上に配置するので、赤いViewのTopとLeadingに各10ずつの制約を設定します。

<img width="448" alt="スクリーンショット 2019-12-21 15 06 20" src="https://user-images.githubusercontent.com/37994872/71304002-8d290900-2403-11ea-9d21-fb12e640dadd.png">

設定した`View.Leading`の制約の詳細を見てみると、`Installed`のチェックが外れていて、`hC`の方の`Installed`はチェックが入っています。

つまり、Vary for Traits機能を使用している時に、新たに設定した制約はVary for Traitsボタンをクリックしたときに表示された吹き出しでチェックを入れた画面サイズでのみ有効になるということです。
（今回は、Heightに選択を入れていたので、`hC`時にのみ有効になる制約ということになります。）

<img width="258" alt="スクリーンショット 2019-12-21 15 11 30" src="https://user-images.githubusercontent.com/37994872/71304048-3839c280-2404-11ea-9598-d796446310b4.png">

そして、制約の一覧で現在表示している画面サイズで有効な制約はアイコンが明るく表示され、無効な制約はアイコンが暗く表示されるので、それでチェックすることもできます。

<img width="346" alt="スクリーンショット 2019-12-21 15 14 47" src="https://user-images.githubusercontent.com/37994872/71304103-420ff580-2405-11ea-8051-0e4b02e3b0a1.png">

この設定が完了すれば、横向きの画面で以下のような表示になります。

<img width="368" alt="スクリーンショット 2019-12-21 15 24 57" src="https://user-images.githubusercontent.com/37994872/71304159-15101280-2406-11ea-9e13-8d1e4a69bbf3.png">

###3.Viewの背景色の変更を設定する
次に横向きの時に、赤いViewの背景色を別の色にしてみましょう。

今度はViewを選択して、Bacgkroundの横の+をクリックして`Add Variation`をクリックします。
<img width="466" alt="スクリーンショット 2019-12-21 15 30 59" src="https://user-images.githubusercontent.com/37994872/71304208-f52d1e80-2406-11ea-9232-a4804e00f14e.png">

`hC`用の背景色設定が表示されるので、適当な色を設定すると、横向きの時にのみその色になります。
<img width="618" alt="スクリーンショット 2019-12-21 15 31 17" src="https://user-images.githubusercontent.com/37994872/71304210-f65e4b80-2406-11ea-9977-5daeaa41efcc.png">

###4.特定のViewを消去・配置する
次は、Viewの上のラベルを設定しましょう。

ラベルには、「300(w)×400(h)」と記載されていますが、横向きの時には、Viewのサイズが300(w)×250(h)なので、「300(w)×250(h)」に変更したいところですが、UILabelのTextは、Vary for Traits機能で差し替えることはできません。

<img width="267" alt="スクリーンショット 2019-12-21 15 38 37" src="https://user-images.githubusercontent.com/37994872/71304286-fa3e9d80-2407-11ea-9fec-00f37cf9b787.png">

なので、今回の場合は「300(w)×400(h)」のラベルを`hC`の時に消去して、「300(w)×250(h)」と記載されたラベルを`hC`の時にのみ表示されるようにすれば望んだ通りの表示になりそうです。

まずは今までの手順と同じように「300(w)×400(h)」ラベルの詳細から、`hC`の`Installed`のチェックを外します。

<img width="250" alt="スクリーンショット 2019-12-21 15 43 51" src="https://user-images.githubusercontent.com/37994872/71304350-c4e67f80-2408-11ea-8042-6de58aafb742.png">
 
すると、ラベルがViewの上から消去されます。
<img width="364" alt="スクリーンショット 2019-12-21 15 46 10" src="https://user-images.githubusercontent.com/37994872/71304385-2a3a7080-2409-11ea-941a-ec4c223bcb2a.png">

あとは、新たにラベルを追加します。

<img width="379" alt="スクリーンショット 2019-12-21 15 49 04" src="https://user-images.githubusercontent.com/37994872/71304397-72f22980-2409-11ea-9670-dd5be3e3b323.png">

制約を追加した時と同じように、新たに追加された「300(w)×250(h)」Labelは`hC`でのみInstalledになります。

<img width="253" alt="スクリーンショット 2019-12-21 15 50 52" src="https://user-images.githubusercontent.com/37994872/71304412-b0ef4d80-2409-11ea-83ca-269f79030d73.png">

制約と同じようにViewも`Installed`かどうかをアイコンの明暗で確認できます。

<img width="359" alt="スクリーンショット 2019-12-21 15 50 01" src="https://user-images.githubusercontent.com/37994872/71304405-91f0bb80-2409-11ea-86f0-d5745981ea0d.png">

###5.Vary for Traitsを終了する
Done VryingをクリックするとVary for Traitsを終了することができます。

<img width="170" alt="スクリーンショット 2019-12-21 15 17 37" src="https://user-images.githubusercontent.com/37994872/71304099-2efd2580-2405-11ea-96b3-968914ae6ae6.png">

###6.確認する
InterfaceBuilderのOrientationを変えて確認してみましょう。
![ VaryForTraits](https://user-images.githubusercontent.com/37994872/71304443-29560e80-240a-11ea-85ad-b0b4a0e3d3d1.gif)

#まとめ
Vary for Traits機能を使うことで、縦画面と横画面それぞれに対応したレイアウトを作成する方法を紹介しました。

自分もこの機能を知るまでは、Viewの比率の制約や、制約のPriorityを細かく設定したり、コードで画面サイズや方向で制約を操作して、複数の画面サイズに対応していましたが、この機能を使うことで、コードを使うことなく、制約もシンプルな形で想定している表示を実現できたので、皆さんも使ってみてはいかがでしょうか？