iPhone6やiPhone6 Plusの出現によって、AutoLayoutの重要性が増してきた。
AutoLayoutを使わずに、ソースレベルで解像度の違いを吸収するのも一つの方法だが、出来るだけ楽をしたいと考えるのが人情というものだろう。

そのAutoLayoutを使っていると、よくわからないものがある。
Constraintに設定するFirst ItemとSecond Itemという項目だ。
ここの設定を間違うとレイアウトは我々が期待していたものとまるで違うものになる。

今回はそこに関して調べてみる。

Viewを画面左端に配置する
まずはViewを画面左端に配置することから始めよう。
このようにViewを一つ配置し、分かりやすいように背景色を赤にしておく。
autolayout_basic_01
次にこのView(以後RedViewと呼ぶ)を左端に配置する設定をする。
以下のようにConstraintを設定しよう。
autolayout_basic_02
これで、幅と高さが100、左上隅にRedViewが配置される。

Viewを水平方向に並べる
次にImageViewを追加し、これをRedViewの右側に並べてみよう。
追加したばかりの状態はこうだ。
ImageViewには適当な画像を設定しておく。
autolayout_basic_03
まず先程と同じ手順で幅と高さのConstraintを設定しよう。
autolayout_basic_04
この段階でプレビューを見るとImageViewはおかしな位置に配置される。
位置に関するConstraintを設定していないのだから、これは当然だ。
autolayout_basic_05
まずは縦位置を揃えてみよう。
以下のようにRedViewとImageViewを選択した状態でAlignボタンを押し、Top Edgesにチェックを入れてAdd 1 Constraintを押す。
autolayout_basic_06
これでプレビューを見ると以下のようになる。
autolayout_basic_07
縦位置が揃っている。
期待通りだ。

次は横位置を設定しよう。
以下のようにCtrlを押しながらImageViewからRedViewにドラッグする。
autolayout_basic_08
すると以下のようなポップアップが表示されるので、Horizontal Spacingを選択する。
autolayout_basic_09
次に、ImageViewを選択した状態でSize Inspectorを開いてみよう。
以下のようになっているはずだ。
autolayout_basic_10
下の方にConstraintの一覧が表示されている。
この中のLeading Space to: Viewという項目をダブルクリックすると以下のようにConstraintの設定する画面が表示される。
autolayout_basic_11
ここで今回の記事の主題であるFirst ItemとSecond Itemが出てきた。
これについては後で触れることにする。
まずはRedViewとImageViewの間に10の隙間を設定したいので、Constantに10を設定しよう。
設定した後にプレビューを見ると期待通りの配置になっていることがわかる。
autolayout_basic_12
今回は上手くいったが、上手くいかない場合もある。
その例を見てみよう。

ImageViewが期待通りの配置をされない場合
それでは主題であるFirst ItemとSecond Itemに迫っていこう。
もう一度Constraintの設定を見てみる。
autolayout_basic_15
First Itemがimage.png.Leadingとなっており、Second ItemがView.Trailingとなっている。
Leadingは左端のことで、Trailingは右端のことだ。
これから考えると、正の方向は右から左に向かうということになる。

つまり、ImageViewの左端から10の位置にRedViewの右端があるということだ。
期待通りの配置にならないのは、大抵ここが正しくない。

配置がおかしくなる典型的な例を見てみよう。
First Itemを選択し、ポップアップからReverse First and Second Itemを選択しよう。
autolayout_basic_16
First ItemとSecond Itemが入れかわり、Constantが-10になっている。
この段階ではプレビューはまだ正常だ。
では、Constantの値を-10から10に変更してみよう。
autolayout_basic_17
プレビューを見るとImageViewがRedViewにめり込んでいるのが確認できる。
RedViewの右端から左に向かって10の位置にImageViewの左端があるということだ。
感覚的には少々わかりづらいが慣れればなんとかなるだろう。

サイズに関するConstraintを設定する。
次はImageViewをRedViewの半分のサイズにしてみよう。

まず、先程の位置に関するConstraintは正しいものに戻しておく。
次にImageViewからRedViewにCtrlを押しながらドラッグし、Equal Widthsを選択する。
autolayout_basic_18
それからこのConstraintの設定画面に行き、Multiplierを0.5にする。
autolayout_basic_19
0.5にすることで半分の大きさにしようというわけだ。
この状態でプレビューを見てみよう。
autolayout_basic_20
我々の期待に反して、ImageViewは半分になるのではなく、倍の幅になってしまっている。
何故だろう。

これを明確にわかりやすくしてくれる解答がstackoverflowにあった。

How to understand auto layout constraint's first item & second Item? - Stack Overflow

ここに以下のような記述がある。
firstItem.firstItemAttribute == secondItem.secondItemAttribute * multiplier + constant
この式に当てはめて考えればスッキリできる。
現状を当てはめてみよう。
RedView.Width == ImageView.Width * 0.5 + 0
となる。

つまり、RedViewの幅が100なので、ImageViewの幅は上記の式に当てはめると200になってしまう。
従って、正しい設定にするにはMultiplierを2にしてやればいい。
RedView.Width == ImageView.Width * 2 + 0
こうすればImageViewの幅は50になる。
autolayout_basic_22


「ImageViewをRedViewの半分にしたいのにMultiplierが2というのは感覚的に変ではないか」と思う人もいるかもしれない。
その場合はReverse First and Second Itemを選んでFirst itemとSecond Itemを入れ替えてみよう。
希望通りの表示になるはずだ。
autolayout_basic_21
この場合、FirstとSecondの設定上の位置が変わるだけで、実際の表示には影響はない。
先程と同じようにMuliplierの値は自動的に0.5に変更されている。

AutoLayoutは複雑なことが多く色々と大変だが、活用できればとても便利なので、是非使い方を覚えていきたい。