iOSアプリのレイアウト事始め
この記事は、モバイルファクトリー Advent Calendar 2015 13日目の記事です。
昨日は @nekobatoさんの 「style-loaderを使ってstylesheetをrequireする」 でした。今日はiosアプリ開発をする際のレイアウト作成に欠かせない要素である、Autolayout
について実作業を交えてお話できればと思います。
目次
準備
iosアプリを開発する際に、実際にアプリのレイアウトを設計するための GUI
として、Xcode
には xib
と storyboard
があります。
実際に表示する画面に対して UIView
や、UILabel
と言ったパーツをドラッグ&ドロップで配置していくことでレイアウトをしていきます。
物は試しと言いますし、実際にやってみましょう。
Xcode
を開いて新規プロジェクト作成。
Sigle Page Application
を選択して、
プロジェクト名は適当に sample
。
Xcode
の左ペインに表示されているファイルツリーから、 Main.storyboard
をクリック。
今回は分かりやすいように iPhone 5/5s/5c
の画面サイズを起点に考えるため、 中央ペインの左側にある Viewツリー
から View Controller
を選択して、
右ペインを下画像のように設定します。
これで View Contoller
(ここでは端末の画面だと思っていただいて大丈夫です) のサイズが iPhone 5/5s/5c
仕様になりました。準備OKです。
レイアウト
いよいよレイアウトしていきます。右下ペインから、配置したいパーツを検索して、ドラッグ&ドロップで配置していきます。今回は UIView
というパーツを配置してみます。
右下ペインから UIView
を検索。
表示された View
を中央ペインの View Controller
にドラッグ&ドロップ。
そのままだと配置した UIView
が分かりにくいので、サイズや色を調整します。
これでレイアウト作業完了です!
後は Xcode
左上から iPhone 5/5s/5c
のどれかのシミュレーターを選んで、 run
ボタンを押して、実際に Simurator
で動作確認してみましょう。
OK!
実は終わりじゃない
できたできた。なーんだ、かんたんじゃーん。 と思っているそこのあなた。
実は終わりじゃないのです。このままだと問題ありです。
試しに別のシミュレーターで起動してみます。
iPhone 5/5s/5c
の画面サイズだと中央に表示されていましたが、 iPhone 6
だと少しズレた所に表示されてしまっています。。
これは困った。
理想としては、以下の様なレイアウトになっていてほしいのです。
Autolayout
ここで登場するのが、iOS6
から導入されたレイアウトシステムである Autolayout
です。
Autolayout
は各Viewに対して「制約」(Constraint)と呼ばれる約束事を指定することで、他Viewのサイズ変更に追従する形で位置やサイズを決定してくれる仕組みです。
それ以前のレイアウトシステムとして Autosizing
というものがありましたが、Autolayout
の登場によってさらに細かいレイアウト指定が可能になりました。
今回は、この Autolayout
を使って、理想としていたレイアウトを実現してみましょう。
まずは配置したViewの位置を指定してあげましょう。 位置は画面の中央に配置したいので、そのように制約をかけます。
配置したViewをクリックして選択した後、中央ペイン右下の Align
ボタンを押します。
すると、他Viewとの位置揃えに関する制約をかけることが出来るAlignメニューが表示されます。
今回は、「親Viewに対して、中央揃えにしたい」ので、Horizontal Center in Container
と Vertical Center in Container
のチェックを付けて、 Add Constraints
ボタンで制約を追加します。
これで iPhone 6
のシミュレーターで実行してみると中央表示になっていることが分かります。
ですが、これだけだと実は問題があります。
中央ペインの左側にある Viewツリー
に赤い矢印のアイコンが表示されています。これは制約が足りない、もしくは制約に矛盾が生じているためのエラーで、実行時に正しいレイアウトになってくれない危険性があることを示しています。
(build出来ないということはないので、今回のように偶然期待通りのレイアウトになってくれることもあります)
アイコンをクリックしてみると、実際のエラー内容を見ることが出来ます。
エラーは2つ。Need constrains for: X position or width
と Need constrains for: Y position or height
。
つまり、指定ViewのX座標もしくは横幅、指定ViewのY座標もしくは縦幅を確定出来るような制約をかけてね、ということです。
つまりは、「このままだと確かに中央に表示されるけど、Viewがどんな形になるか分かんないよ。いいの?」って言ってくれてるわけです。親切ですね。
良くないので、Viewの形もしっかり確定させてあげます。
理想としては160x160の正方形になっていてほしいので、そのように制約をかけてみましょう。
また配置したViewを選択した後、Align
ボタンの隣りにある Pin
ボタンを押します。
Width
と Height
を160に指定して、チェックした後 Add Constraints
ボタンで制約を追加します。
これで先ほどあったエラーアイコンが消えて、画面から不安な赤色が消えました。
この状態が、適切に制約をかけられている状態になります。
これでどの画面サイズに対しても、「中央表示で160x160固定」なViewが表示されるようになりました。やったね。
制約の指定で気をつけること
慣れない内は制約を指定してもエラーや警告が消えずに四苦八苦すると思います。(僕がそうだったので)
なので、僕が制約の指定に慣れることが出来た考え方を紹介できればなと思います。
制約の指定は全てのViewを配置し終わってから一気にやる
指定された制約は、Viewの位置・サイズの変化等によって、追従して勝手に変わることが多々あります。
つまり、Viewを配置しながら制約も一緒に指定しているときに、「あ、このViewのサイズはこうじゃないや」とサイズ変更すると、今まで指定してきた制約が警告を発し始め、アワアワしてしまいます。その後の一つ一つ制約の警告を消していく作業が面倒くさい。
Update frames
や、 Update constraints
によって自動で警告を消すように調整してくれる機能はありますが、把握していない箇所で意図しない変更が加えられる可能性があるので基本使わないようにしています。
また、Viewの階層を変更すると、そのViewのみに指定された制約はそのままに、そのViewと以前制約をかけあっていたViewの制約は消えてしまいます。
つまり、Viewを配置しながら制約も一緒に指定しているときに、「あ、このViewの階層はここじゃないや」と階層を変更すると、(ry
要するに、警告解消作業が面倒くさいので、制約の指定は全てのViewを配置し終わってViewのサイズや位置を変更しないようにしてから一気にやるのが安全性が高いです。
指定の順番は親Viewから順に
Viewの制約は、基本的に自身か親View、もしくは同階層のViewに対してかけることが多いです。
なので、一番上の階層にあるViewから順番に制約をかけていくと、エラーや警告に怒られることなく制約追加を進めることが出来ます。
また、そうすることでそのViewを他の箇所にも使いたいと思った時に、最上位のViewのみ制約が壊れるので、そのViewのみエラー/警告を解消してやればコピペしやすくなります。
「位置」と「形」の可能性を潰す
なにも制約を指定していない状態というのは、「どんな位置にもどんな形にもなる可能性のあるView」であることが言えます。そんなものはレイアウトしているとは言えません。
なので、まず「位置」の可能性を潰します。
今回のように水平方向と垂直方向の中心になるような制約を指定してあげれば、そのViewが存在しうるのは画面中央しかあり得なくなります。
次に「形」の可能性を潰します。
このままでは、ものすごく縦長のViewでも横長のViewでも制約をクリアしてしまうので、縦幅と横幅を160で固定してしまいました。
そうすることで、そのViewの形は160x160の正方形でしかあり得なくなります。
こういう具合で、制約を追加する時は、そのViewの「位置」と「形」が1つの可能性に収束するかどうかを見るようにしています。
終わりに
Autolayout
についての解説記事は多くありますが、今回はプロジェクト作成からレイアウトまで、順番に一連の流れを簡単にですが解説させていただきました。
実際のアプリ開発では今回のようなシンプルなUI構成ではないことが多いですが、基本的にレイアウトの作業は今回のサイクルの繰り返しになります。なので、今回のような手順を自然に出来るようになれば、iosアプリのレイアウト初級には入門出来たのではないでしょうか。
次回は @pine613さんの 「Kotlinの拡張関数について」 です!