FlexBoxと比較しながらUIStackViewマスターになる
1. はじめに
僕はよくCSSを書き、それなりにできるので今回は比較しながら書ければいいなと思います。
今回は以下のようなフォームの一番下にあるテキストとリンクが混じったものをUIStackView
というものを使って実装していきます。
2. UIStackViewとは
iOS9から導入されたレイアウトのために使うクラスです。
UIKit
のモジュールであり、Auto LayoutをsubViewの管理を自動で行ってくれます。
2.1 対応するCSSのプロパティ
Flexboxが非常にUIStackViewのスタックという考え方に似ています。
display: flex
2.2 メリット
以下のようなメリットがあります。
- StackViewでコンポーネントを分けることができる
- subViewのレイアウトを簡単に決められる
- スタックの中にスタックと重ねることができる
- 少ない制限で使える
- サイズクラスをサポートする
- などなど
2.3 デメリット
- すでに配置されたサブビュー取り除いてしまう:
addArrangedSubviews
とあるが、実際に行っているのはaddSubView
である。 - 制約を壊すかもしれない: UIStackViewではどれが制約を壊すかを知ることは難しいです。
- 細かい制約を課すには逆に使いにくいかもしれない。
- などなど
3. UIStackViewのプロパティ
3.1 Axis
axis
はsubViewをどのような軸でレイアウトするかというもの。
水平方向のhorizontal
と、垂直方向のvertical
があります。
flex-flow: /* row か column */
に対応します。
3.2 Distribution
distribution
はaxis
で指定した主軸の方向にどのように配置をするかを指定します。
これはcssのjustify-content
で指定できるものです。
Mysteries of Auto Layout, Part 1 - WWDC 2015 - Videos - Apple Developer
から引用すると
のように指定できます。
CSSとの対応表は以下にまとめました。
UIStackView(iOS) | Flexbox(CSS) |
---|---|
fill |
なし |
fillEqually |
space-around |
fillProportionally |
なし。しかし別途flex プロパティが設定された状態 |
equalSpacing |
space-between |
equalCentering |
なし。 |
では、これ以外にはどのようにしたらいいでしょうか。
Flexboxでいう、、、
justify-content: flix-start
これはStackViewの幅を設定しなければ実現することができます。
というのも、同じdistributionをfill
にしても幅を変更することによって対応できます。
widthAnchor
を指定したり、centerXAnchor
を指定すると以下のようになります。
それをleadingAnchor
にすると以下のようになります。
基準を変えることで実現できます。
3.3 Spacing
subViewの間での余白を指定します。
CSSで言う所のmargin
を指定するようなものでしょうか。
.parent .child p hoge .child p fuga .child p copi
だとすると
.parent { display: flex, flex-flow: row, justify-content: space-between, & > div { margin: 0px { right: 10px, left: 10px, } } }
のような感じではないでしょうか。
3.4 Alignment
axis
がhorizontal
のときはtop
, center
, bottom
, fill
を指定することができて、vertical
の時はleading
,center
,trailing
,fill
を指定することができます。
Horizontal
Vertical
これはcssでいうalign-item
のことです。
項目が多いので割愛するが、詳しく知りたい人は参考文献をご覧ください。
3.5 DistributionとAlignmentがどっちがどっちか忘れる
CSSでも「あれ、justify-contents
かalign-items
かどっちを指定すればよかったっけ?」と最初のころはなっていました。
distribution
やjustify-contents
は主軸の方向に定めるものです。
行として並べていたら縦にどのように配置するか、列としてして並べていたら横にどのように配置するか**を指定することになります。
alignment
やalign-items
は、主軸方向と垂直にどのように並べるかを決めます。
配置したものを、どこ基準で配置するかを主軸と垂直方向で考えるのです。
4 実装パート
4.1 UIStackViewを使って定義
以下のように定義します。
また、ここでのbutton
はStackView`の上にあるボタンのことです。
private let signupStackView = UIStackView() self.signupStack.axis = .horizontal self.signupStack.alignment = .center self.signupStack.distribution = .fill self.view.addSubView(signupStackView) signupStackView.addSubView(self.label) signupStackView.addSubView(self.button) self.signupStack.topAnchor.constraint(equalTo: self.button.bottomAnchor, constant: 50.0).isActive = true self.signupStack.widthAnchor.constraint(equalToConstant: formWidth).isActive = true self.signupStack.centerXAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.centerXAnchor).isActive = true
すると以下のようになりました。
まとめ
だんだん制約がきつくなって、テストを書かないと不安になってきました。
またここらへんから、どこを基準に制約を掛けるかもチームなどの運用で大事になってくるのではと感じました。 あくまでも相対的なものなので、
参考文献
公式ドキュメント
UIStackView - UIKit | Apple Developer Documentation
全般的にこれ一つの記事ですべてがわかるもの
Distributionについて詳細に書かれてあるもの
同様にDistributionについてわかりやすい
よくあるUIStackViewの間違いを指摘
CSSのFlexboxについて