UIStackView
iOS9から、UIStackViewというコンポーネントが追加されるので触ってみました。
ざっくり言えば、UIStackViewに子Viewがaddされた時、子Viewの位置、サイズを自動的に決定してくれるという代物です。
UIStackViewは基本的にAutoLayout下で使用する前提のようで、各Viewの制約(Constraints)をもとにサイズの決定などを行います。
自動配置ルールの設定
UIStackViewを親Viewとして、子Viewの配置設定はdistributionというプロパティにより決定されます。
[self.stackView setDistribution:UIStackViewDistributionEqualCentering];
distributionには5つの設定があり、それぞれが以下のようなルールを持っています。
Fillから始まる設定では、各子ViewはUIStackViewの向きに従い
領域いっぱいを埋めるように拡大/縮小されます。
- Fill / UIStackViewDistributionFill
- 親Viewのサイズが大きく、子Viewのサイズを広げなければ領域いっぱいにならない場合、子Viewの中で最もContent Compression Resistance Priorityの低いものが拡大されます。
- 親Viewのサイズが小さく、子Viewのサイズを縮めなければいけない場合、子Viewの中で最もContent Hugging Priorityの低いものが縮小されます。
-
Fill Equal / UIStackViewDistributionFillEqually
- 子View全ての高さが等しくなるよう調整します。
-
Fill Proportional /UIStackViewDistributionFillProportionally
- 要調査。詳細に分かり次第追記したいです。
- 名前やReference的に、中の子Viewのサイズ比が変わらないように拡大縮小するのかなと思ったらそうでもない挙動をする。。
Equalから始まる設定では、各子View間の位置関係が設定通りになるようにViewの位置が調整されます。
-
Equal Spacing / UIStackViewDistributionEqualSpacing
- 各子View同士の間隔が等しくなるように位置が調整されます。
-
Equal Centering / UIStackViewDistributionEqualCentering
- 各子Viewの中心座標同士の間隔が等しくなるように位置が調整されます。
addArrangedSubview:
自動配置させたい子Viewをコードから追加する場合、*addArangedSubview:*で行います。
addArrangedSubView:で追加されたViewは、UIStackViewがVerticalなら一番下、
Horizontalなら一番右に配置されます。
またinsertArrangedSubview:atIndex:で途中に差し込むことも可能です。
*addSubview:*では通常通りの子View追加となり、自動配置は行ってくれません。
removeArrangedSubview:
また、*removeArrangedSubview:*で自動配置対象からそのViewを外すことができます。
removeArrangedSubview:しただけでは子ViewはUIStackViewから取り除かれません。
このとき子Viewのサイズ計算は解除され、単純にaddSubView:された状態となります。
子ViewをUIStacViewから取り除きたい場合は、通常通りその子ViewからremoveFromSuperViewを呼び出してやる必要があります。
この場合でも残った子Viewで配置の再計算を行ってくれます。
hiddenによる子View操作
子Viewに対してsetHidden:などを行った場合も、そのViewが存在しない状態での配置計算を行ってくれます。(AndroidでいうGONEのイメージ)
この機能により、条件分けで表示したりしなかったりするレイアウトの実現がかなり簡単になるかと思われます。
設定変更時にアニメーション
各ViewのConstraintが調整されるので、明示的にアニメーションするようlayoutIfNeededを呼び出してやれば滑らかに変化させることができます。
(リサイズされてからアニメーションが始まる場合もあるためView内容に注意は必要そうですが)
[self.stackView addArrangedSubview:view];
[UIView animateWithDuration:1.0f
animations:^{
[self.stackView layoutIfNeeded];
}
hiddenの場合は[UIView animateWithDuration:animations:]で囲えば滑らかにやってくれます。
[UIView animateWithDuration:1.0f
animations:^{
[self.hiddenLabel setHidden:!_hiddenLabel.hidden];
}];
おわりに
そのまま使えば勝手に均等配置してくれますし、
最後尾にContent Compression Resistance PriorityとContent Hugging Priorityを最低に設定したダミーViewを置いておけば
名前通りaddしたViewをスタックしてくれて便利そうだなあと思いました。
iOS9からというのがまだ微妙ですが、機会があれば出し分けが必要な場面で使いたいです。