アクトインディ開発者ブログ

子供とお出かけ情報「いこーよ」を運営する、アクトインディ株式会社の開発者ブログです

よく使う Auto Layout のテクニック集

iOS のアプリ開発を担当している namikata です。アクトインディに入社して、アプリ開発を担当するようになって 2 年強が経ちました。アプリの新規リリースから運用まで携わらせてもらう中で AutoLayout と向き合う事も多く、よく使う AutoLayout のテクニックをまとめていきたいと思います。

目次

  1. View を使った複数要素のセンタリング
  2. CustomView の高さを修正の度に変更したくないので Bottom >= 0 の制約で回避
  3. CustomView の Self-Sizing
  4. View の高さを複数の制約の優先度をコントロールして変更する
  5. tableView を Grouped にして、上下に余白を設ける

View を使った複数要素のセンタリング

画像とテキストなど横並びにしてセンタリングしたいケースなどでよく使います。StackView に入れて StackView をセンタリングするだけです。

f:id:t-namikata:20180816133714g:plain

CustomView の高さを修正の度に変更したくないので Bottom >= 0 の制約で回避

色んな画面で使うパーツは CustomView にして使い回すことが多いと思いますが CustomView の高さを AutoLayout で決定させる為に Bottom の制約が必要になる際に使えるテクニックです。

f:id:t-namikata:20180816133755g:plain

ScrollView + StackView の作り方

最近やっと慣れてきましたw

f:id:t-namikata:20180816134012g:plain

  1. ScrollView は縦だけでなく横にも Scroll できるので、縦のスクロールのみできるように 親View と scrollView で EqualWidth
  2. scrollView の中の要素は横にスクロールできる ScrollView の性質の影響を受けるので CenterX

CustomView の Self-Sizing

他の画面で使い回したい要素だから CustomView に切り出そうと思った時に、いつも頭をよぎるのが Auto Layout の問題でした。CustomView を作成した場合に StoryBoard で CustomView を放り込むと Y ポジションの制約を求められます。CustomView にする前は View の中に配置した要素の制約により、親 View の高さが決まっていた為、警告は出ませんでしたが、CustomView にすると View の中の要素は StoryBoard は認識しないので、高さの制約が必要になります。

f:id:t-namikata:20180816133858p:plain

高さの制約を与えると CustomView の高さを変更した時に、使っている箇所全ての高さを変更しなくちゃ行けない問題が出てしまうので、そんな時に使えるテクニックです。StackView を活用することになります。

f:id:t-namikata:20180816134104g:plain

  1. 動的に高さを管理したい CustomView を StackView の中に入れる
  2. StackView の Distribution を Equal Spacing にする

ビルドするといい感じになります。

f:id:t-namikata:20180816134140p:plain

View の高さを複数の制約の優先度をコントロールして変更する

ある条件によって View の高さを変えたい時に height 制約をコードで変更する事がありますが、以下のようにやってしまうと Storyboard で指定した高さの制約と二重管理になってしまいます。

@IBOutlet weak var viewHeightConstraint: NSLayoutConstraint!
if isEmpty {
    viewHeightConstraint.constant = 10
} else {
    viewHeightConstraint.constant = 100
}

最近は NSLayoutConstraint の isActivate を切り替える事で高さの切り替えを行う事が多いです。

  1. Storyboard で優先度 1000 と 750 の制約をそれぞれ設定し、優先度 1000 の方を IBOutlet で結ぶ

f:id:t-namikata:20180816134203p:plain

  1. コードで高さを切り替える
@IBOutlet var viewHeightConstraint: NSLayoutConstraint! // weak はつけない
viewHeightConstraint.isActive = false // 優先度 1000 の制約を無効にする事で 優先度 750 の制約が適用される

注意点としては weak をつけると isActivate を切り替えた際に、インスタンスが解放されてしまうので weak 設定はしません。画面切り替わり時に deinit が呼ばれ ViewController がきちんと破棄されていたので多分大丈夫。詳細はこちらにものっています https://stackoverflow.com/questions/38051879/why-weak-iboutlet-nslayoutconstraint-turns-to-nil-when-i-make-it-inactive

f:id:t-namikata:20180816134221g:plain

tableView を Grouped にして、上下に余白を設ける

時々スクロール領域内に余白を設けたい事があり、このテクニックを使います。

f:id:t-namikata:20180816134242g:plain

  1. TableView の Style を Grouped にする
  2. TableView の背景色を変更する
  3. Header の高さを変更したい場合はコードで指定する

なぜか Header の高さが storyboard で指定しても効きません。なんでだろう。高さを変えたい時はコードで指定してあげる必要があります。

func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
    return 50
}

f:id:t-namikata:20180816134321g:plain

最後に

今回利用したコードは github に上がっていますので、もしよかったらどうぞ。

アクトインディでは、一緒に働いてくれるエンジニアを募集しております。 興味のある方はぜひお越しください!