#Swiftのレイアウトで詰まったポイント
swiftのレイアウト周りで詰まったので、備忘録もかねてまとめておこうと思います。swift5、Xcode12です。storyboardやswiftUIではなく、swift(コード)で書いています。(storyboardやswiftUI使えば凄い楽なんですけどね…レイアウトにこだわるとコードで書くのが一番良いらしいです。)
#viewDidLoad内で、viewのwidthなどが0になってしまい取得できない
上記の通りですが、下記のコードのようにviewDidLoad内でview1のwidthとheightの値が0になってしまい、view2が描画できていません。
view.backgroundColor = UIColor.lightGray
let view1 = UIView()
let view2 = UIView()
self.view.addSubview(view1)
self.view.addSubview(view2)
view1.translatesAutoresizingMaskIntoConstraints = false
view1.backgroundColor = UIColor.green
view1.widthAnchor.constraint(equalTo: self.view.widthAnchor, multiplier: 0.5).isActive = true
view1.heightAnchor.constraint(equalTo: self.view.heightAnchor, multiplier: 0.5).isActive = true
view1.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
view1.centerYAnchor.constraint(equalTo: self.view.centerYAnchor).isActive = true
view2.translatesAutoresizingMaskIntoConstraints = false
view2.backgroundColor = UIColor.blue
view2.frame.size.width = view1.frame.size.width / 2
view2.frame.size.height = view1.frame.size.height / 2
//view1のwidthとheightは0になってしまう
view2.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
view2.centerYAnchor.constraint(equalTo: self.view.centerYAnchor).isActive = true
viewDidLoad内でview1に対して、view1.widthAnchor.constraint()を用いてオートレイアウトを使った。そして、そのviewのwidthの値を用いて、下記の方法でview2の長さを決めようとした。
#原因
原因は、制約やレイアウトが反映されていないため。viewDicLoad内でviewに制約を加えても、その場では更新されない。
#解決策
###1. レイアウトでのサイズ指定(widthやheight)をせずに、制約としてサイズの指定をする。
AnchorやNSLayoutConstraintで制約を指定する。
//widthやheightでレイアウトの指定をしない
view2.widthAnchor.constraint(equalTo: self.view.widthAnchor, multiplier: 0.4).isActive = true
view2.heightAnchor.constraint(equalTo: self.view.heightAnchor, multiplier: 0.4).isActive = true
###2. 制約やレイアウトを更新する。
レイアウトが更新されないなら、そのタイミングで更新するだけ。
下記コードではうまく更新できない。タイミングの問題かと思い、色々なタイミングで実行したけどできない。なんでだろ?
self.view.updateConstraintsIfNeeded()
self.view.layoutIfNeeded()
#まとめ
奥が深いなぁ…
下記引用です。
- Viewの読み込み
- 制約の追加(AutoLayout)
- 制約を元にViewのframeを計算(レイアウト)
- frameの位置に描画(レンダリング)
という順番で読み込むので、オートレイアウトがされ、frameの値が決められた後にframeを直接編集するとオートレイアウトで決定した制約が死んでしまうのかな…なるほど?
#今後の課題
基本的にはオートレイアウトですべて決定するのが良さそう…?
もしくは、他のオートレイアウトの方法との組み合わせはいける?
widthAnchorやheightAnchorのAnchorについても今度調べようかなと思いました。
#参考文献
viewのライフサイクル
viewのライフサイクル2
オートレイアウト(Anchor)
オートレイアウト(NSLayoutConstraint)
レイアウトと制約の更新
レイアウト・制約・描画のタイミングなど