きっかけ
先日ViewをUIStackViewで並べて挙動を確認しようと思ったら思い通りに動きませんでした。UIStackViewには縦か横かの方向を決めるaxisプロパティ、どこに揃えて並べるかを決めるalignmentプロパティ、どのように並べるかを決めるdistributionプロパティがあるのですが、axis、alignmentはともかくdistributuonが少し難解。「fillとfillProportinalliyってどうちがうん?」と思いサンプルアプリを作ってみたことがきっかけになりました。
UI部品はそれぞれ大きさを持っている
UI 部品はその中身によって大きさが異なります。UILabelであれば、中身のtextが長くなるにつれて、それを表示するためのUIViewも大きくなります。
let あ : UILabel = {
let label = UILabel()
label.text = "あ"
return label
}()
let あい : UILabel = {
let label = UILabel()
label.text = "あい"
return label
}()
let あいう : UILabel = {
let label = UILabel()
label.text = "あいう"
return label
}()
print(あ.intrinsicContentSize)//(16.0)
print(あい.intrinsicContentSize)//(31.5,20.0)
print(あいう.intrinsicContentSize)//(47.5,20.0)
あ、あい、あいうとしてUILabelを作成しそれぞれのintrinsicContentSizeを表示させると、高さは変わりませんが幅は一文字あたり約16ptずつ大きくなっていることがわかります。これらはtextという中身によって定まるもの(intrinsic: 形 固有の、本質的な)なので、UILabelのframeを大きくしても変化することはありません。
ここまで書いたことはUILabelがUIViewをサブクラスに持っていることを考えればすごく当たり前のことかもしれませんが。。。
UIViewのintrinsicContentSizeは?
UIViewはどうなっているのでしょうか。
let view = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
print(view.intrinsicContentSize)//(-1.0,-1.0)
(-1,-1)と決まっているようです。
intrinsicContentSizeを変更する
intrinsicContentSizeをoverrideします。
class View: UIView {
override var intrinsicContentSize: CGSize {
return CGSize(width: 100, height: 100)
}
}
print(View().intrinsicContentSize)//(100.0,100.0)
intrinsicContentSizeを自由に定める
initに引数を加えてintrinsicContentSizeを自由に決められるようにしてみました。
class View: UIView {
let width: CGFloat
let height: CGFloat
init(frame: CGRect,size: CGSize) {
self.width = size.width
self.height = size.height
super.init(frame: frame)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override var intrinsicContentSize: CGSize {
return CGSize(width: width, height: height)
}
}
print(CGSize(width: 10, height: 10))//(10.0,10.0)
今のところは使い所が不明ですが。