【Swift】超便利StackViewの実践的使い方!まだAutoLayoutで消耗してるの?

  • 146
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

まだAutoLayoutで消耗しているの?

AutoLayout...。それは今までエンジニアの寿命を縮めてきたものです。こんな経験ありませんか?

Twitterのようなタイムラインを作ろう!!
以下のようなタイムラインを考えてみます。

スクリーンショット 2016-03-21 18.46.12.png

ツイートには画像があるものと無いものがあります。つまり、異なるレイアウトのセルを2つ用意して、場合分けして表示させる方法が一般的でしょう。どちらのセルにもAutoLayoutを設定しなければなりません。ツイートテキストのラベルの高さを可変になになるように設定したり、大変ですよね。

これだけではありません。タイムラインの仕様変更がありました。
『そうだ!リツイートや、ファボができるようにボタンを配置しよう!』
『...』
『AutoLayout付け直し...?オワタ』

スクリーンショット 2016-03-21 18.53.40.png

このようにAutoLayoutは今まで僕らの寿命を縮めてきました。

救世主StackViewの登場

ここでは、上で出てきたタイムラインをStackViewを使ってレイアウトの設定をしていきます。
StackViewの特徴は以下のようなものです。

  • AutoLayoutの設定が最小限に抑えられる
  • hiddenプロパティに対応
  • 部品を再配置がし易い(編集しやすい)
  • 慣れれば超簡単
  • イライラしない
  • ステキ
  • 好きになっちゃう

実践あるのみ。StackViewを使ってタイムラインを作ってみる

セルのレイアウトはxibファイルを使用して作っていきます。

普通に部品を配置する

まずは必要な部品を適当に配置します。(分かりやすく背景色をつけています)

スクリーンショット 2016-03-21 19.05.53.png

ツイート画像を表示するためのImageViewもここで配置しておきます。

StackViewを使う

StackViewを使用する時のポイントは以下の点です。

  • StackViewは部品を暖かく包み込むように使用する
  • 垂直方向、水平方向に並んでいる部品をそれぞれ包み込む

部品同士を暖かく包み込む

まずは小さなグループを見つけます。nameLabelとtimeLabelは水平方向に並んでいるのでStackViewで包み込んであげます。

スクリーンショット 2016-03-21 19.16.30.png

すると小さなStackViewの中にnameLabelとtimeLabelが包み込まれた状態になります。このStackViewをSmallStackViewと呼びましょう。

次に少し大きなグループを見つけます。
SmallStackView, textLabel, tweetImageViewがそれぞれ垂直方向に並んでいるのでStackViewで包み込んであげます。

スクリーンショット 2016-03-21 19.22.51.png

ここで作成したStackViewをMediumStackViewと呼びましょう。
最後にMediumStackViewとiconImageViewが水平方向に並んでいるので、StackViewで包み込んであげます。

スクリーンショット 2016-03-21 19.25.26.png

ここで作成されたStackViewをLargeStackViewと呼びましょう。

StackViewを設定すると部品が少し変な配置になってしまいますが、今はこのままでOKです。

ViewControllerのソースコード

ViewController.swift

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("TweetCell", forIndexPath: indexPath) as! TweetCell
        let tweet = self.tweets[indexPath.row]
        cell.iconImageView.image = tweet.icon
        cell.nameLabel.text = tweet.name
        cell.timeLabel.text = tweet.time
        cell.tweetLabel.text = tweet.text
        cell.tweetImageView.hidden = true
        if let image = tweet.tweetImage {
            cell.tweetImageView.hidden = false
            cell.tweetImageView.image = image
        }
        return cell
    }


このようにツイート画像がある時と無い時でhiddenプロパティを切り替えます。
hiddenにした部品はStackView内では存在しない事として扱われます。つまり、画像が含まれないツイートはImageViewが存在しないように振る舞ってくれます。
これによってセルを2つ用意する必要が無くなります。便利便利便利。

最低限のAutoLayoutを設定しましょう

LargeStackViewの大きさをセルの大きさと一致させるためにLargeStackViewにAutoLayoutを設定します。

制約は上下左右の余白をゼロとして設定します。
ここまでできたら一旦Runしてシミュレータで確認してみます。

スクリーンショット 2016-03-21 19.31.17.png

見るも無残なモンスターが生まれてしまいました。

部分的にAutoLayoutを設定する

アイコンがとっても大きいのでAutoLayoutを設定しましょう。
アイコンに対してwidthとheightの値を具体的に設定し制約を追加します。

スクリーンショット 2016-03-21 19.32.50.png

ちょっと綺麗になりました。
次にツイート画像の高さが大きすぎるので、ツイート画像のImageViewにもAutoLayoutを設定します。

スクリーンショット 2016-03-21 19.36.16.png

だいぶ良くなってきました。
しかし、名前、時間、テキストのラベルが不格好なので整頓していきましょう。

StackView内の部品の整列させる

MediumStackViewの中の部品をそれぞれ整頓させていきたいです。
そこで、StackViewのAlignmentを設定します。
AlignmentをFillに設定しましょう。

スクリーンショット 2016-03-21 19.39.25.png

めちゃ良い感じになってきました。
しかし、このままですと部品同士がくっついていて窮屈です。そこで余白を設定してみましょう。

部品同士に余白を設定する

余白を設定するためにはStackViewのSpacingを設定します。
以下の画像のようにStackViewにSpacingを設定すると、StackViewに包まれている部品に余白を付けることができます。

スクリーンショット 2016-03-21 19.45.47.png

これで、とってもスッキリして気持よくなりました。
これで終わりでも良いのですが、この状態から新たに部品を配置してみたいと思います。

部品を追加する

ここでは、セルの下部にリプライ、リツイート、ファボの3つのボタンを配置します。

既存のStackViewに新たに部品を配置する。

MediumStackViewはSmallStackView, textLabel, tweetImageViewを垂直方向に配置させているものでした。このMediumStackView内に新たにButtonを配置します。

スクリーンショット 2016-03-21 19.55.43.png

次に、配置したButtonから水平方向に続くようにもう2つButtonを配置したい所です。
2つ目のButtonを配置する前に1つ目のButtonをStackViewで包んであげます。
この時StackViewのAxis属性をHorizontalに設定しましょう。ボタンを水平方向に配置していきたいからです。

スクリーンショット 2016-03-21 20.01.46.png

ここで作成したStackViewの中に残り2つのボタンを配置します。

スクリーンショット 2016-03-21 20.04.30.png

上の画像のようにDistributionをFill Equallyに設定します。すると3つの部品のWidthが均等になるように配置してくれます。超便利です。

完成です。

スクリーンショット 2016-03-21 20.51.04.png

ちなみに、画面を横に回転させても自動でレイアウトし直してくれます。とっても助かります。

スクリーンショット 2016-03-21 21.42.39.png

最後に

最後にポイントをおさらいです。

  • StackViewは水平方向、垂直方向に並んでいる部品同士を暖かく包み込むように使用する
  • hidden = trueを設定した部品は、その部品が存在しないようにレイアウトされる
  • StackViewの大きさは中の部品の大きさ(テキストの量や画像サイズ)に依存する
  • 特定の部品の大きさを制御したい場合は部分的にAutoLayoutを設定する。
  • SpacingによってStackView内の部品同士の余白を設定する
  • StackViewのアトリビュートインスペクタをイジイジすることで様々なパターンの整列を行うことができる(幅均等など)
  • 画面回転時に自動でレイアウトし直してくれる。

アプリのソースコードはコチラ