ストーリーボードでAutolayout

Xcode 5.1.1

我々はもうAutolayoutから逃げることはできない。

今からでもAutolayoutを使うことに慣れていくしかない。以下にAutolayoutを使った具体的なデザイン例と手順を掲載しておくので、Autolayoutにまだ不慣れだというひとに、チュートリアルとして参照していただきたい。


iPhoneでこんな画面を作ってみたとする。

【4インチ画面】

右上にヘッダ、左下にフッタ、中央にメインコンテンツを配置している。

この画面をAutolayoutを使わずに、絶対座標で作ったとすると、デバイスを横向きにしたときにレイアウトが崩れてしまう。

【4インチ画面 - 横向き】

アプリのビルド設定で横向きに対応しないという手もあるが、今の時代はもう、デバイスによって画面のアスペクト比が異なる。ご存知のように、iPhone5, 5c, 5s(4インチ)向けにレイアウトした画面をiPhone 4s以前(3.5インチ)デバイスで表示すると、画面下部が切り捨てられてしまう。

【3.5インチ画面】

iPhone 5が出た当初あたりはまだ、3.5インチ向けに画面をデザインして、4インチでは画面下部が切り捨てられても構わないようにレイアウトすることもあったかもしれないが、もうそういう時代ではなくなってきた。

仕方がないのでAutolayoutを使ってみよう。

今回のレイアウト要件を以下のように定義してみた。

【今回のお題】

  • ヘッダ部の幅と高さは固定であるとする。
  • ヘッダ部の幅とフッタ部の幅は同じサイズであるとする。
  • ヘッダ部の高さとフッタ部の高さは同じサイズであるとする。
  • ヘッダ部は画面の上から8px、右から8pxの位置に配置することとする。
  • フッタ部が画面の下から8px、左から8pxの位置に配置することとする。
  • メインコンテンツ部は左右8pxのマージンを取り、上部はヘッダ部の下から8px、下部はフッタ部の上から8pxの位置に配置する。


さて、初めてAutolayoutを使うとき、初手からして何をすれば良いのかわからずに、硬直してしまうのは私だけではないだろう。Storyboard上でAutolayoutを定義する初手としては、次の2通りがある。

【2通りの初手】
・画面下の「Align」ボタンを押す。
・画面下の「Pin」ボタンを押す。

上記SSにわかりやすくAlignボタン(赤)とPinボタン(紺)の位置に目印をつけておいた。

【AlignとPinでできること】

  1. 1つのオブジェクトを選択して、「Pin」を選択し、オブジェクトの固定幅、固定高さを定義する。
  2. 1つのオブジェクトを選択して、「Pin」を選択し、オブジェクトの親ビューの上下左右に対するそれぞれの間隔を定義する。
  3. 2つのオブジェクトを選択して、「Pin」を選択し、2つのオブジェクトの幅や高さを同じ値に設定する。
  4. 2つのオブジェクトを選択して、「Align」を選択し、2つのオブジェクト間の位置関係を定義する。

細かくいえばもっとあるかもしれないが、まずはこのくらいのことができると覚えておけばよいだろう。


さて、それではさっそく、ヘッダ部からレイアウトしていく。

・ヘッダ部のビューを選択する。
・Pinアイコンをクリックする。
・制約を設定するダイアログが出るので、以下のようにする。

親ビューの上から8px、右から8pxの幅をセット。(上と右への点線が赤い実線に変わったことに注目)
幅を160px、高さを44pxにセットして、「Add 4 Constraints」を押す。

ストーリーボードの構造ツリーを展開すると、4つの制約が出来ていることがわかる。

ここで右上に、黄色い右矢印が表示されているかと思う。この黄色い矢印は警告である。こいつをクリックすると、たとえば以下のような警告メッセージが表示されるだろう。

Misplaced Views
Label - Header
Expected:x=152,y=28,width=160,height=44
Actual:x=150,y=25,width=158,height=37

この警告は、(ドラッグ&ドロップで)初期配置したときのビューの絶対座標と、Autolayoutの制約がずれていますよ、という内容である。Headerを選択して、Size Inspectorを使って、制約と不整合が起きないように座標とサイズを調整してやれば解決する。Actualが絶対座標なので、Autolayoutに合わせるには、絶対座標をExpectedの方に合わせてやる。


同様の手順で今度はフッタ部の制約をセットする。

・フッタ部のビューを選択する。
・Pinアイコンをクリックする。
・制約を設定するダイアログが出るので、以下のようにする。

親ビューの下から8px、左から8pxの幅をセット。(下と左への点線が赤い実線に変わったことに注目)
この時点ではまだフッタ部の幅と高さを設定していない。
以下の手順でフッタ部のサイズをヘッダ部のサイズに合わせてやる。

・ヘッダ部のビューとフッタ部のビューを両方選択する。(Command + Click)
・Pinアイコンをクリックする。
・Equal WidthsとEqual Heightsにチェックを入れてAdd 2 Constraintsを押す。
・フッタ部を選択して、Size Inspectorで座標とサイズ調整を行う。
(Expectedの方に合わせてやること)


最後にメインコンテンツ部分に制約をつける。

・ヘッダ部のビューとメインコンテンツのビューを両方選択する。(Command + Click)
・Alignアイコンをクリックする。
・Trailing EdgesとTop Edgesにチェックを入れてAdd 2 Constraintsを押す。

Trailing Edgesは右端を合わせる設定であり、Top Edgesは上端を合わせる設定であるが、この時点では「どこからどこへ」という設定がうまくいっていない。Trailing Edgesから修正してみよう。

・画面左のビュー構造を展開して、
View Controller → View → Constraints 内の目的のTrailing Alignmentを選択する。

・画面右側のAttributes Inspectorを開く。
・First ItemにMain.Trailingを選択する。
・Second ItemにHeader.Trailingを選択する。
(FirstとSecondが逆になっている場合は、Reverse First And Second Itemを選択する)
・Constraintの値に0をセットする。

同様の手順で、Top Alignmentの制約を修正する。

・画面左のビュー構造を展開して、
View Controller → View → Constraints 内の目的のTop Alignmentを選択する。

・画面右側のAttributes Inspectorを開く。
・First ItemにMain.Topを選択する。
・Second ItemにHeader.Bottomを選択する。
(FirstとSecondが逆になっている場合は、Reverse First And Second Itemを選択する)
・Constraintの値に8をセットする。


これでヘッダ部とメインコンテンツ間の制約ができた。

続けて、フッタ部とメインコンテンツ間の制約を定義する。今度は、メインコンテンツ部のLeading(左端)をフッタ部のLeading(左端)に合わせて、さらにメインコンテンツ部の下部をフッタ部の上8ピクセル手前までと定義する。作業手順は、ヘッダ部とメインコンテンツ間の制約を定義したときとほとんど同じである。

・フッタ部のビューとメインコンテンツのビューを両方選択する。(Command + Click)
・Alignアイコンをクリックする。
・Leading EdgesとBottom Edgesにチェックを入れてAdd 2 Constraintsを押す。

・画面左のビュー構造を展開して、
View Controller → View → Constraints 内の目的のLeading Alignmentを選択する。

・画面右側のAttributes Inspectorを開く。
・First ItemにMain.Leadingを選択する。
・Second ItemにFooter.Leadingを選択する。
(FirstとSecondが逆になっている場合は、Reverse First And Second Itemを選択する)
・Constraintの値に0をセットする。

・画面左のビュー構造を展開して、
View Controller → View → Constraints 内の目的のBottom Alignmentを選択する。

・画面右側のAttributes Inspectorを開く。
・First ItemにMain.Bottomを選択する。
・Second ItemにFooter.Topを選択する。
(FirstとSecondが逆になっている場合は、Reverse First And Second Itemを選択する)
・Constraintの値に-8をセットする。

最後に、警告を参照しながら、メインコンテンツ部のSize Inspectorを開いて、座標とサイズを調整する。


これでようやく完成した。

Storyboard上で意図した通りにきれいにレイアウトできていることを確認してみたら、早速シミュレーターで実行してみよう。

【4インチ画面】

【4インチ画面 - 横向き】

【3.5インチ画面】

【3.5インチ画面 - 横向き】


だいぶ面倒だったが、どうにか思い通りのレイアウトはできた。だが、この程度のレイアウトはまだまだ序の口で、実際のところ、Autolayoutはもっと奥深いというか、謎めいているというか、特にスクロールビューのZoom(拡大縮小)とデバイスの回転が重なるととんでもなく面倒なことになる。その辺の話は、また別に機会にでも。




それでは。
楽しい時間でした!
またの機会を!