AutoLayoutを使っているとLandscapeとPortraitでレイアウトを分けたくなることがある。
例えばこのような感じだ。
LandscapePortrait_02


LandscapePortrait_01
Landscapeの時はMenuが画面の左側に配置され、Portraitの時はMenuが上側に配置される。
これをAutoLayoutで実現する方法を見ていく。
 
Size Classesとは
Size Classesは簡単に言うと、色んな解像度別にAutoLayoutが適用される仕組みだ。
これについての詳細な言及は避けるが、以下のページの解説がわかりやすい。

[iOS 8] マルチデバイス対応の新機能「Trait Collection」 | Developers.IO

横や縦の解像度に応じてRegularとCompactと判別され、それに応じたレイアウトが適用される。
(特に意識せずにAutoLayoutを使うと全解像度で共通のレイアウトになる。)

組み合わせは以下の4通りになる。
※iPhone5と5SはSEと同じ、iPhone6と6Sと7は同じ、iPhone6Plusと6SPlusと7Plusは同じ
  • wC hC(width: Compact, height: Compact)…iPhone4S, SE, 7のLandscape時
  • wR hC…iPhone7 PlusのLandscape時
  • wC hR…iPhone4S, SE, 7, 7 PlusのPortrait時
  • wR hR…iPad(Landscape, Postraitどちらも)
iPhoneSE等がPortrait時はwC hRなのにLandscape時はwR hCではなくwC hCなのはいささか気持ち悪さを感じる。
しかしそう決められている以上、これは仕方のないことだ。
とにかくこの4通りでレイアウトを定義してやればいい。

今回やりたいことを考えると、iPhone(全機種)のPortrait時はMenuが上でContentが下に表示(以降縦レイアウトとする)され、それ以外の時はMenuが左でContentが右に表示(以降横レイアウトとする)されればいいし、iPadはどの方向でも横レイアウトとするので4通りではなく2通り考えれば良い。
つまり、wC hRの時とそれ以外の時だ。
では実際にその2つのケースでの制約を付けていこう。

なお、今回行うXcodeのバージョンは8.2.1だ。
将来的には今回のやり方から変わる可能性は非常に高いので注意したい。

2通りの制約を作成する
まずは基本の制約を作成しよう。
基本は横レイアウトとし、wC hRの時のみ縦レイアウトとする。
これは重要で、基本を縦レイアウトにしてしまうと制約の作成がめんどくさいことになる。
今回はそこについては触れないが、興味がある方は実際にやってみればめんどくささを実感できるだろう。

まずStoryboardでLandscapeを選択し、新しいViewControllerに2つのUILabelを追加する。
LandscapePortrait_03
次にMenuに以下の様にTop, Left, Bottomが0、幅が100の制約を追加する。
LandscapePortrait_04
同じ様にContentはTop, Left, Right, Bottomが0となるような制約を追加する。
その結果、このようになるはずだ。
LandscapePortrait_05
これをPreviewで見てみよう。
LandscapePortrait_06
LandscapePortrait_07

左からiPhoneSE, iPhone7 Plus, iPadとなっており、それぞれの縦と横の時だ。
ここまではいいだろう。
次にwC hRの時の制約を追加しよう。

LandscapePortrait_08

OrientationでPortraitを選択し、右側にある"Vary for Traits"というボタンを押す。
すると、以下の様なポップアップが現れるのでWidthとHeightどちらもチェックする。
LandscapePortrait_09
View asの欄を見ると、複数のケースが表示されているが、これがこれから定義するケースだ。
LandscapePortrait_10
Split Viewのケースも表示されているが、今回は関係ないので気にしない。

なお、この状態で制約やViewを変更しても、適用されるのは現在選択しているケース(wC hR)のみである。
それを踏まえて縦レイアウトを設定していこう。

まずMenuを選択してSize Inspectorを開こう。
5つの制約が並んでいるはずなので、一番上のものを選択してdeleteボタンを押す。
すると以下の様にグレーアウトされるはずだ。
LandscapePortrait_11
同様に他の4つも全て同じ様にする。

deleteを押すと制約が削除されるのではないかと思ってしまうかもしれないが、今はVaryingを行っている状態なので、"wC wRの時はこの5つの制約は使わない"ということを設定しているわけだ。

同様にContentの制約も全て削除する。
これでMenuとContentには制約が一切ない状態になったので、縦レイアウトを実現するための制約を追加しよう。

なお、制約を追加しやすいように、前もって以下の様に手動で配置しておけば色々とやりやすい。
LandscapePortrait_12
MenuはTop, Left, Rightが0、Heightが100
ContentはTop, Left, Right, Bottomが0
とする。

その結果、以下の様になったはずだ。
LandscapePortrait_13
これで制約は追加できたので、Done Varyingを押して処理を完了する。
LandscapePortrait_14
それではPreviewを見てみよう。
LandscapePortrait_15
LandscapePortrait_16
縦向きの場合はiPhoneは縦レイアウト、iPadは横レイアウト
横向きの場合は全ての端末が横レイアウトになっている。
期待通りの結果を得ることができた!