前回のつづき。

今回はAuto Layoutの基礎的な部分を説明していきたいと思います。

サンプルコード: https://github.com/stack3/iOSAutoLayoutSamples

サンプルコードのSTBasicViewController.storyboardを開いてみましょう。

01

このように4つのLabelが配置されています。

サンプルコードを起動し、Baisc Layoutを選択します。以下の画面が表示されます。Simulatorを4-inchで起動した場合です。

02

Storyboardに配置した位置と異なり、Label2がLabel1より上にありNavigation Barの下に隠れています。

横画面にしてみましょう。

04

Label1とLabel4は幅が伸びました。Label2はNavigationBarに隠れたまま、Label3は画面から消えてしまいました。
※ 実際にはLabel3画面の下にはみ出しています。

Label1とLabel4が意図したように表示されるのはAuto Layoutがうまく働いているからです。

Constraint

STBasicViewController.storyboardを開きましょう。Label1を選択すると左右に青い線があります。

03

この線のことをConstraintと呼びます。Constraintとは制約という意味です。Auto LayoutではViewとViewの間隔やViewのサイズなどを、このConstraintによって決定します。

左の青い線(Constraint)を選択します。

05

これはViewとLabelの左端の間隔を、この幅で固定することを意味しています。

Attributes Inspectorを開きます。

06

Constraint 20になっています。つまり幅20pxを固定するということです。

次に右の青い線を選択します。

07

Attributes Inspectorを開きます。

08

こちらもConstraint 20になっています。つまりLabelの右端とViewの間隔を20pxで固定するということです。
横画面になったときLabel1が横に伸びるのは、左右の間隔を20pxで固定するConstraintが働いているからです。

次に上端の横線を選択します。

10

Attributes Inspectorを開きます。

11

Constraint 0になっています。これは上端との間隔を0pxで固定するということです。

Storyboard上はStatusBar真下に配置されていますが、実際はこのConstraintの働きによってNavigationBarが表示されている場合は、その下に表示されます。これはTop Layout Guideというものが関係しているのですが、それは後述します。

Label1を選択して、Size Inspectorを開き、Constraintsの項目を見てみましょう。

09

それぞれ以下の意味を表します。

Leading Space to: Top Layout Guide LabelのTop Layout Guideとの上端間隔を0pxで固定
Trailing Space to: Superview
Equals: 20
LabelのSuperviewとの右端間隔を20px固定
Leading Space to: Superview
Equals: 20
LabelのSuperviewとの左端間隔を20px固定

このようにConstraint単体でのプロパティだけでなく、View(この場合Label)がそのConstraintをひもづいているかも確認できます。

自分でConstraintを設定してみる

Label2を選択してみましょう。

12

見ての通りConstraintがありません。このままだと横画面にしても幅が固定されたままです。

Label2を選択した状態で画面下のPinボタンをクリックしてください。

10

以下のようなポップアップが表示されます。

11

Viewから伸びる左右の点線をクリックしてConstraintを選択、Add 2 Constraintsボタンを押します。

12a

Label2の左右にConstraintが設定されました。

13

しかし、Constraintがオレンジ色になっています。Label1は青色でした。

よく見ると左サイドのViewの右側に赤い矢印が表示されています。

14

赤い矢印を押すとスライドして以下の画面になります。

15

Need Constrains for: Y positionとあります。つまりY座表示(垂直方向)のConstraintが必要だけどありませんよ、という警告です。

Constraintを追加して、まだAuto LayoutがConstraintを必要とする時は、Constraintがオレンジ色になると覚えておいてください。

Label2を選択して、上端を固定するConstraintを追加してみましょう。

16

Label1とLabel2の間にConstraintができました。また全てのConstraintが青色になりました。

14

これでLabel2はLabel1と8pxの間隔で固定されます。

このようにConstraintは基本的に水平方向、垂直方向、両方を設定する必要があります。

さてサンプルコードを起動して、横画面にしてみます。

15

今度はLabel2も横に伸びましたね。

自分でConstraintを設定してみる その2

Label4を選択してみましょう。

16

Constraintが左右と下に設定されています。このおかげでLabel4は横画面にしたり、端末のサイズが変わっても左右の間隔、下からの位置が固定されます。

Label3を選択してみましょう。

17

何もConstraintがありません。このままだとxib上で配置した位置で常に固定されます。よって横画面にしたとき、画面の高さが狭くなるのでLabel3は画面下へはみ出てしまいます。

Label3がLabel4の上に表示されるようにConstraintを設定しましょう。

Label3を選択して、Pinボタンを押します。そしてConstraintを以下のように選択して、Add 3 Constraintsボタンを押します。

18

以下のようにLabel3のConstraintが設定されます。

19

起動して確認してみましょう。

20

正しく表示されていますね!

横画面にしてみます。

21

幅が伸びて左右の間隔が固定され、かつ、Label4との間隔も固定されたままです。

Constraintの値を設定してみる

Label3の左のConstraintを選択します。

22

Attributes Inspectorを選択し、Constantを10に変更します。

26

同様にLabel3の右のConstraintも10にしてみましょう。

Label3とConstraintは、このようになります。

23

起動して確認してみましょう。

左右の間隔が10pxになり、Label3の幅が広くなりました。

24

横画面にしても、左右の間隔は10pxのままです。

25

他にもConstraintの値を調整してみて、レイアウトが変わることを確認してみると良いでしょう。

Viewの移動とConstraintの更新

Viewの位置やサイズを変更したい時があります。

Label3を上の方へ移動してみましょう。

26

Label4との間隔を示すConstraintがオレンジ色になりました。また過去の位置がオレンジの点線枠で表示されています。

オレンジ色のConstraintを選択して、そのAttributes Inspectorを確認してみると、8pxのままになっています。

32

つまり、一度設定したConstraintはレイアウト上でViewを移動しても変わることがありません。実際のConstraintとレイアウト上に差異があるときは、このようにオレンジ色で警告表示されます。

起動してみても、Constraintが変わっていないことが確認できます。

24

Constraintを変更するためには、Label3を選択して、画面下の以下のボタンを押します。このボタンはResolve AutoLayout Issuesと言います。

33

メニューが現れるので、Update Constraintを選択します。

34

するとオレンジ色だったConstraintが青色になります。

27

起動してみると、Label3とLabel4の間の間隔が広がっています。

28

Top Layout Guide

一番上に配置するSuperviewは、基本的にTop Layout Guideを起点としてConstraintを設定します。

Label1を選択してResolve Auto Layout Issuesボタンを押して、Clear Constraintsを選択します。

09

Label1のConstraintが削除されました。

31

Pinボタンを押して一番上の数値の横にあるプルダウンを押します。以下のメニューが表示されます。

32

 

ここにViewとTop Layout Guideという項目があります。デフォルトではTop Layout Guideが選択(チェックが入っている)されています。

Top Layout Guideが選択されていると、上端のConstraintはStatusBarかNavigationBarどちらか表示されている方が起点となります。逆にViewが選択されている場合は、View(Labelから見てSuperview)の上端が起点となります。

最初に配置していたLabel 1はTop Layout Guideが起点だったのでNavigationBarの下に表示されていました。今回はViewを起点とするとどう変わるかを確認してみましょう。

先ほどのプルダウンからViewを選択します。

33

 

するとConstraintの数値が0から20に変わりますが、とりあえずそのままにしておきましょう。

34

左右のConstraintも設定してAdd 3 Constraintを押してConstraintを追加します。

35

このようになります。

36

 

上端のConstraintに注目してください。Viewの上端に向かって線が伸びています。

37

Top Layout Guideを起点としていたときは、StatusBarの下に横線が表示されていました。

10

現在のViewを起点としている状態で起動してみましょう。

38

Label1が消えてしまったように見えますが、実際は場所はStatusBarの真下に表示されてNavigationBarの下に隠れてしまっています。

iOS 7からViewControllerのViewは全画面表示になりStatusBar、NavigationBarの下に重なって表示されています。Viewを起点としてConstraintを20pxに設定したので、Viewの上端から20px下、つまりStatusBarの下に表示されることになります。

多くの場合は、このように表示されると都合が悪いのでTop Layout Guideを起点とすべきです。実際、Storyboard上でもそれがデフォルトになっています。ただし、ScrollViewやそのSubclassの場合、Viewを起点とした方が良い場合もあります。

Layout GuideはiOS 7でViewが全画面表示になったことで導入された概念です。詳しくは以下の記事を参考にしてください。ScrollViewやToolbarと重ならない方法(Bottom Layout Guide)についても書いています。

iOS 7の全画面対応

Storyboardに戻ってLabel1を選択、Resolve Layout IssuesボタンのClear ConstraintsでConstraintを削除しましょう。

31

Pinボタンを押して今度はデフォルトのままTop Layout Guideにします。

39

上と左右のConstraintを設定し、Add 3 Constraintsを押します。

40

見ての通りConstraintの表示も元に戻りました。

10

起動すると今度はLabel1はNavigationBarの下に表示されています。

28

Storyboard上でNavigationBarを表示する

Storyboard上ではStatusBarしか配置されていないので、実際NavigationBarの下に配置されることに違和感を感じるかもしれません。その場合は、Viewを選択、Attributes InspectorからTop BarをTranslucent Navigation Barなどに変更するという手もあります。

41

そうするとStoryboardのViewにNavigationBarが表示されます。

42

ただし、すでにSubviewを配置している状態で、これをするとこのようにNavigationBarと重なってしまうので再配置が必要です。

43

この方法でNavigationBarを表示するのは、Storyboard上でシミュレートするためのものです。実際にNavigationBarが表示されるかどうかと関係がないことに注意です。個人的にはこの機能は使わないようにしています。ViewControllerごとに対応するのは面倒ですし、Top Layout Guideの概念を理解しておけば、この対応をしなくとも問題ないはずですから。

以上、Auto Layoutの基本的な説明でした。

その3へつづく