まだAutoLayoutで消耗しているの?
AutoLayout...。それは今までエンジニアの寿命を縮めてきたものです。こんな経験ありませんか?
Twitterのようなタイムラインを作ろう!!
以下のようなタイムラインを考えてみます。
ツイートには画像があるものと無いものがあります。つまり、異なるレイアウトのセルを2つ用意して、場合分けして表示させる方法が一般的でしょう。どちらのセルにもAutoLayoutを設定しなければなりません。ツイートテキストのラベルの高さを可変になになるように設定したり、大変ですよね。
これだけではありません。タイムラインの仕様変更がありました。
『そうだ!リツイートや、ファボができるようにボタンを配置しよう!』
『...』
『AutoLayout付け直し...?オワタ』
このようにAutoLayoutは今まで僕らの寿命を縮めてきました。
救世主StackViewの登場
ここでは、上で出てきたタイムラインをStackViewを使ってレイアウトの設定をしていきます。
StackViewの特徴は以下のようなものです。
- AutoLayoutの設定が最小限に抑えられる
- hiddenプロパティに対応
- 部品を再配置がし易い(編集しやすい)
- 慣れれば超簡単
- イライラしない
- ステキ
- 好きになっちゃう
実践あるのみ。StackViewを使ってタイムラインを作ってみる
セルのレイアウトはxibファイルを使用して作っていきます。
普通に部品を配置する
まずは必要な部品を適当に配置します。(分かりやすく背景色をつけています)
ツイート画像を表示するためのImageViewもここで配置しておきます。
StackViewを使う
StackViewを使用する時のポイントは以下の点です。
- StackViewは部品を暖かく包み込むように使用する
- 垂直方向、水平方向に並んでいる部品をそれぞれ包み込む
部品同士を暖かく包み込む
まずは小さなグループを見つけます。nameLabelとtimeLabelは水平方向に並んでいるのでStackViewで包み込んであげます。
すると小さなStackViewの中にnameLabelとtimeLabelが包み込まれた状態になります。このStackViewをSmallStackViewと呼びましょう。
次に少し大きなグループを見つけます。
SmallStackView, textLabel, tweetImageViewがそれぞれ垂直方向に並んでいるのでStackViewで包み込んであげます。
ここで作成したStackViewをMediumStackViewと呼びましょう。
最後にMediumStackViewとiconImageViewが水平方向に並んでいるので、StackViewで包み込んであげます。
ここで作成されたStackViewをLargeStackViewと呼びましょう。
StackViewを設定すると部品が少し変な配置になってしまいますが、今はこのままでOKです。
ViewControllerのソースコード
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してシミュレータで確認してみます。
見るも無残なモンスターが生まれてしまいました。
部分的にAutoLayoutを設定する
アイコンがとっても大きいのでAutoLayoutを設定しましょう。
アイコンに対してwidthとheightの値を具体的に設定し制約を追加します。
ちょっと綺麗になりました。
次にツイート画像の高さが大きすぎるので、ツイート画像のImageViewにもAutoLayoutを設定します。
だいぶ良くなってきました。
しかし、名前、時間、テキストのラベルが不格好なので整頓していきましょう。
StackView内の部品の整列させる
MediumStackViewの中の部品をそれぞれ整頓させていきたいです。
そこで、StackViewのAlignmentを設定します。
AlignmentをFillに設定しましょう。
めちゃ良い感じになってきました。
しかし、このままですと部品同士がくっついていて窮屈です。そこで余白を設定してみましょう。
部品同士に余白を設定する
余白を設定するためにはStackViewのSpacingを設定します。
以下の画像のようにStackViewにSpacingを設定すると、StackViewに包まれている部品に余白を付けることができます。
これで、とってもスッキリして気持よくなりました。
これで終わりでも良いのですが、この状態から新たに部品を配置してみたいと思います。
部品を追加する
ここでは、セルの下部にリプライ、リツイート、ファボの3つのボタンを配置します。
既存のStackViewに新たに部品を配置する。
MediumStackViewはSmallStackView, textLabel, tweetImageViewを垂直方向に配置させているものでした。このMediumStackView内に新たにButtonを配置します。
次に、配置したButtonから水平方向に続くようにもう2つButtonを配置したい所です。
2つ目のButtonを配置する前に1つ目のButtonをStackViewで包んであげます。
この時StackViewのAxis属性をHorizontalに設定しましょう。ボタンを水平方向に配置していきたいからです。
ここで作成したStackViewの中に残り2つのボタンを配置します。
上の画像のようにDistributionをFill Equallyに設定します。すると3つの部品のWidthが均等になるように配置してくれます。超便利です。
完成です。
ちなみに、画面を横に回転させても自動でレイアウトし直してくれます。とっても助かります。
最後に
最後にポイントをおさらいです。
- StackViewは水平方向、垂直方向に並んでいる部品同士を暖かく包み込むように使用する
-
hidden = true
を設定した部品は、その部品が存在しないようにレイアウトされる - StackViewの大きさは中の部品の大きさ(テキストの量や画像サイズ)に依存する
- 特定の部品の大きさを制御したい場合は部分的にAutoLayoutを設定する。
- SpacingによってStackView内の部品同士の余白を設定する
- StackViewのアトリビュートインスペクタをイジイジすることで様々なパターンの整列を行うことができる(幅均等など)
- 画面回転時に自動でレイアウトし直してくれる。