161
140

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

遅ればせながら UIStackView 入門

Posted at

仕事で関わっているプロジェクトはiOS8のサポートを打ち切ったこともあり、2016年の師走に今更ながらUIStackViewについて調べてみました。

UIStackViewとは

  • AutoLayoutのラッパークラス
  • iOS9以上で利用可能
  • 煩雑な制約を使わずに複数のViewを水平/垂直方向にレイアウト可能
  • デバイスの回転、スクリーンサイズなどに動的に対応可能
Horizontal Vertical
axis-horizontal.png axis-vertical.png

レイアウトに関わるプロパティ

UIStackViewは主に次の4つのプロパティを使って設定します。

  • axis alignment distribution spacing

axis

var axis: UILayoutConstraintAxis

サブビューを X軸方向に並べる場合は horizontal、 Y軸方向に並べる場合は vertical を指定します。

alignment

var alignment: UIStackViewAlignment

axis と垂直軸方向におけるサブビューの配置方法を指定します。

axishorizontal の場合、top center bottom fill が指定可能です。
また、vertical の場合、 leading center trailing fill が指定可能です。
fill 以外に関しては、各サブビューは Intrinsic Content Size に基づいてサイズが決定されます。
fill では、axisとの垂直方向の領域を埋めるようにして各ビューがリサイズされます。

axis: .horizontal の場合
alignment-horizontal.png
axis: .vertical の場合
alignment-vertical.png

distribution

var distribution: UIStackViewDistribution

axis 方向におけるサブビューの配置方法を指定します。

fill fillEqually FillProportionally EqualSpacing EqualCentering が指定可能です。

  • fill

    • hugging priority compression resistance priority を元にサブビューをリサイズします。曖昧な場合、 arrangedSubviews (後述) の順に基づいてサブビューをリサイズします。
  • fillEqually

    • 各ビューを同一幅で配置します。
  • fillProportionally

    • Intrinsic Content Size に応じて幅が決まる
    • 各サブビューは係数(StackViewの幅 / 各サブビューの幅の総和 ?)をかけてリサイズされる
  • equalSpacing

    • Intrinsic Content Size に応じて幅が決まる
    • サブビュー間のスペースを等間隔に配置
  • equalCentering

    • 各サブビューの中心を等間隔に配置
    • サブビューの幅の総和がStackViewより大きい場合、幅はリサイズされる。`
axis: .horizontal の場合
distribution-horizontal.png
axis: .vertical の場合
distribution-vertical.png

spacing

var spacing: CGFloat

サブビュー間の余白を指定します。 distributionequalSpacingequalCentering の場合、無視されます。

サブビューの管理方法

UIStackViewはUIViewのサブクラスのため subviews プロパティを持ちますが、実際のレイアウトは arrangedSubviews プロパティのサブビューが対象となります。
arrangedSubviews への追加は addArrangedSubview() を利用します。arrangedSubviewssubviews のサブセットのため、このメソッド経由で追加されたビューは subviews に追加されます。
なお、 ビューを addSubview()subviews に追加しただけでは arrangedSubviews には追加されず、UIStackViewでのレイアウト制御の対象として扱われないので注意が必要です。

UIStackViewの作り方

UIStackViewを使って次のようなビュー構成を作る場合のサンプルです。
(※Storyboardの場合の例は割愛)

make-programatically.png
let view = UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 50))
view.backgroundColor = UIColor.white

/// Instantiate StackView and configure it
let stackView = UIStackView(frame: .zero)
stackView.axis = .horizontal
stackView.alignment = .center
stackView.distribution = .fill
stackView.spacing = 20
stackView.translatesAutoresizingMaskIntoConstraints = false

view.addSubview(stackView)

/// Setup StackView's constraints to its superview
view.topAnchor.constraint(equalTo: stackView.topAnchor).isActive = true
view.bottomAnchor.constraint(equalTo: stackView.bottomAnchor).isActive = true
view.leadingAnchor.constraint(equalTo: stackView.leadingAnchor).isActive = true
view.trailingAnchor.constraint(equalTo: stackView.trailingAnchor).isActive = true


/// Add subviews
let switchh = UISwitch()
switchh.isOn = true
switchh.backgroundColor = UIColor.cyan
stackView.addArrangedSubview(switchh)

let label = UILabel()
label.backgroundColor = UIColor.magenta
label.text = "label"
stackView.addArrangedSubview(label)

let button = UIButton(type: .infoDark)
button.backgroundColor = UIColor.yellow
stackView.addArrangedSubview(button)

その他

サブビューの isHidden プロパティに対応しています。
isHiddenfalsetrue に変えるだけでStackView上から非表示にでき、かつ他のサブビューが再レイアウトされます。

所感

簡単で使いやすいとは昨年から見聞きしてましたが、全くその通りでした。
大抵のレイアウトはUIStackViewで実装できそうな気がします。
iOS8のサポートを打ち切ったプロジェクトでは使わない理由はありませんね。


Credit(画像アイコン)

161
140
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
161
140

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?