StackView.destributionわかったかも!
「StackViewのfillProportionallyちょっとわかったかも。要はStackViewの大きさと中身が揃ってない時中身の比を考慮して敷き詰めてくれるって感じね。Playgroundsでサンプル作って動かそ」
5つのUIViewを用意してwidthAnchorとheightAnchorをそれぞれを100pt×100ptにして、`addArangeSubView`して。。。
import PlaygroundSupport
import UIKit
class View: UIView {
let stackView = UIStackView()
let redView = UIView()
let orangeView = UIView()
let yellowView = UIView()
let greenView = UIView()
let blueView = UIView()
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .white
setupStackView()
setupColorViews()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupStackView() {
stackView.backgroundColor = .white
stackView.axis = .horizontal
stackView.alignment = .fill
stackView.distribution = .fillProportionally
addSubview(stackView)
stackView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
stackView.centerYAnchor.constraint(equalTo: self.centerYAnchor),
stackView.centerXAnchor.constraint(equalTo: self.centerXAnchor),
stackView.widthAnchor.constraint(equalTo: self.widthAnchor)
])
}
private func setupColorViews() {
redView.backgroundColor = .red
orangeView.backgroundColor = .orange
yellowView.backgroundColor = .yellow
greenView.backgroundColor = .green
blueView.backgroundColor = .blue
let colorViews: [UIView] = [redView,orangeView,yellowView,greenView,blueView]
colorViews.forEach { view in
NSLayoutConstraint.activate([
view.widthAnchor.constraint(equalToConstant: 100),
view.heightAnchor.constraint(equalToConstant: 100)
])
stackView.addArrangedSubview(view)
}
}
}
「あれ??大きさを考慮して敷き詰めるなら100:100:100:100:100 = 1:1:1:1:1だから等間隔に敷き詰められるんじゃないの?」
調べてみると
どうやらfillProportionallyが比の参考にするのはframeのsizeではなく、intrinsicContentSizeらしい。当たり前といえば当たり前なのかも。
「なるほど。じゃあintrinsicContentSizeを100pt×100ptにしてみよ」
色と大きさを指定できるUIViewを作成
class ColorView: UIView {
var size: CGSize
init(color: UIColor, size: CGSize) {
self.size = size
super.init(frame: CGRect())
backgroundColor = color
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override var intrinsicContentSize: CGSize {
return CGSize(width: size.width, height: size.height)
}
}
これを水平方向の画面いっぱいに広がるStackViewに入れる
class View: UIView {
let stackView = UIStackView()
let redView = ColorView(color: .red, size: CGSize(width: 100, height: 100))
let orangeView = ColorView(color: .orange, size: CGSize(width: 100, height: 100))
let yellowView = ColorView(color: .yellow, size: CGSize(width: 100, height: 100))
let greenView = ColorView(color: .green, size: CGSize(width: 100, height: 100))
let blueView = ColorView(color: .blue, size: CGSize(width: 100, height: 100))
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .white
setupStackView()
setupColorViews()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupStackView() {
stackView.backgroundColor = .white
stackView.axis = .horizontal
stackView.alignment = .fill
stackView.distribution = .fillProportionally
addSubview(stackView)
stackView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
stackView.centerYAnchor.constraint(equalTo: self.centerYAnchor),
stackView.centerXAnchor.constraint(equalTo: self.centerXAnchor),
stackView.widthAnchor.constraint(equalTo: self.widthAnchor)
])
}
private func setupColorViews() {
let colorViews: [UIView] = [redView,orangeView,yellowView,greenView,blueView]
colorViews.forEach { view in
stackView.addArrangedSubview(view)
}
}
}
「これでできるはず...」
PlaygroundPage.current.liveView = View()
「おーできた」
fillProportionallyらしいコーディングをしてみる
「widthの実際の値をもとにした比に基づいてwidthが定まるのがfillProportionallyだった」
let redView = ColorView(color: .red, size: CGSize(width: 1, height: 100))
let orangeView = ColorView(color: .orange, size: CGSize(width: 2, height: 100))
let yellowView = ColorView(color: .yellow, size: CGSize(width: 3, height: 100))
let greenView = ColorView(color: .green, size: CGSize(width: 4, height: 100))
let blueView = ColorView(color: .blue, size: CGSize(width: 5, height: 100))
なら、これは1:2:3:4:5になるはず
「おー、なってるやん。fillPortionally完全に理解できたわ!」
ソースコード
Playgrounds上でコピペで動きます。
import PlaygroundSupport
import UIKit
class ColorView: UIView {
var size: CGSize
init(color: UIColor, size: CGSize) {
self.size = size
super.init(frame: CGRect())
backgroundColor = color
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override var intrinsicContentSize: CGSize {
return CGSize(width: size.width, height: size.height)
}
}
class View: UIView {
let stackView = UIStackView()
let redView = ColorView(color: .red, size: CGSize(width: 1, height: 100))
let orangeView = ColorView(color: .orange, size: CGSize(width: 2, height: 100))
let yellowView = ColorView(color: .yellow, size: CGSize(width: 3, height: 100))
let greenView = ColorView(color: .green, size: CGSize(width: 4, height: 100))
let blueView = ColorView(color: .blue, size: CGSize(width: 5, height: 100))
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .white
setupStackView()
setupColorViews()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupStackView() {
stackView.backgroundColor = .white
stackView.axis = .horizontal
stackView.alignment = .fill
stackView.distribution = .fillProportionally
addSubview(stackView)
stackView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
stackView.centerYAnchor.constraint(equalTo: self.centerYAnchor),
stackView.centerXAnchor.constraint(equalTo: self.centerXAnchor),
stackView.widthAnchor.constraint(equalTo: self.widthAnchor)
])
}
private func setupColorViews() {
let colorViews: [UIView] = [redView,orangeView,yellowView,greenView,blueView]
colorViews.forEach { view in
stackView.addArrangedSubview(view)
}
}
}
PlaygroundPage.current.liveView = View()