viewDidLoad内で、viewのwidthなどが0になってしまい取得できない(Swiftの画面レイアウト周りの備忘録) 

#Swiftのレイアウトで詰まったポイント
swiftのレイアウト周りで詰まったので、備忘録もかねてまとめておこうと思います。swift5、Xcode12です。storyboardやswiftUIではなく、swift(コード)で書いています。(storyboardやswiftUI使えば凄い楽なんですけどね…レイアウトにこだわるとコードで書くのが一番良いらしいです。)

#viewDidLoad内で、viewのwidthなどが0になってしまい取得できない
上記の通りですが、下記のコードのようにviewDidLoad内でview1のwidthとheightの値が0になってしまい、view2が描画できていません。

~~~swift

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

~~~

上記コードの実行結果：
[](![simulator_screenshot_B400A3C0-4B91-4450-9B39-2DFEA2D1B83C.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1230993/c0eb9038-5fd3-5765-8e66-fa3513c067b6.png))
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1230993/c0eb9038-5fd3-5765-8e66-fa3513c067b6.png" width="400">


期待される結果：
[](![simulator_screenshot_52CFDAAA-EA29-4EA3-9307-55D4323DE2DA.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1230993/3418494b-b650-3997-5d7d-2d482f2a7cdb.png))

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1230993/3418494b-b650-3997-5d7d-2d482f2a7cdb.png" width="400">


viewDidLoad内でview1に対して、view1.widthAnchor.constraint()を用いてオートレイアウトを使った。そして、そのviewのwidthの値を用いて、下記の方法でview2の長さを決めようとした。


#原因　
原因は、**制約やレイアウトが反映されていないため**。viewDicLoad内でviewに制約を加えても、その場では更新されない。

#解決策
###1. レイアウトでのサイズ指定（widthやheight）をせずに、制約としてサイズの指定をする。
AnchorやNSLayoutConstraintで制約を指定する。

~~~swift
//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. 制約やレイアウトを更新する。
~~レイアウトが更新されないなら、そのタイミングで更新するだけ。~~
下記コードではうまく更新できない。タイミングの問題かと思い、色々なタイミングで実行したけどできない。なんでだろ？

~~~swift
self.view.updateConstraintsIfNeeded()
self.view.layoutIfNeeded()
~~~

#まとめ
奥が深いなぁ…
下記引用です。

- Viewの読み込み
- 制約の追加（AutoLayout）
- 制約を元にViewのframeを計算（レイアウト）
- frameの位置に描画（レンダリング）

という順番で読み込むので、オートレイアウトがされ、frameの値が決められた後にframeを直接編集するとオートレイアウトで決定した制約が死んでしまうのかな…なるほど？

#今後の課題
基本的にはオートレイアウトですべて決定するのが良さそう…？
もしくは、他のオートレイアウトの方法との組み合わせはいける？
widthAnchorやheightAnchorのAnchorについても今度調べようかなと思いました。

#参考文献
[viewのライフサイクル](https://medium.com/eureka-engineering/ios%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E5%BF%85%E8%A6%8B-ios%E3%81%AE%E3%83%AC%E3%82%A4%E3%82%A2%E3%82%A6%E3%83%88%E3%81%A7%E6%8A%BC%E3%81%95%E3%81%88%E3%81%A6%E3%81%8A%E3%81%8D%E3%81%9F%E3%81%84%E3%81%93%E3%81%A8-%E7%B7%8F%E9%9B%86%E7%B7%A8-b25342566ccc)
[viewのライフサイクル2](https://qiita.com/shtnkgm/items/f133f73baaa71172efb2)
[オートレイアウト(Anchor)](https://medium.com/eureka-engineering/ios%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E5%BF%85%E8%A6%8B-ios%E3%81%AE%E3%83%AC%E3%82%A4%E3%82%A2%E3%82%A6%E3%83%88%E3%81%A7%E6%8A%BC%E3%81%95%E3%81%88%E3%81%A6%E3%81%8A%E3%81%8D%E3%81%9F%E3%81%84%E3%81%93%E3%81%A8-%E7%B7%8F%E9%9B%86%E7%B7%A8-b25342566ccc)
[オートレイアウト(NSLayoutConstraint)](https://techblog.recochoku.jp/7727)
[レイアウトと制約の更新](https://xyk.hatenablog.com/entry/2015/10/30/000350)
[レイアウト・制約・描画のタイミングなど](https://qiita.com/koutEngineerK/items/6989fc27137137fa304a)