発生している問題点
AutoLayoutで配置せずにコードで自作したViewを
AutoLayoutを使用して配置したViewの位置を参照して描画する際,アプリを実行した時にレイアウトが崩れる問題
具体的に言うとAutoLayoutで配置しているスライダーの位置を取得してそれの割合で自作のViewを描画するプログラムを書いた時に発生した問題
StoryBoardで設定しているiPhone11では正常に描画
Simulator→iPhone8でレイアウトが崩れる
なぜ起きたか?
結論→View描画のライフサイクル を理解していなかった。
- スライダーMaxPointを取得する際に現在設定しているのStoryBoardのポイントを取得
以下のコードは自作Viewを作成する際に使用したコード
イニシャライザにスライダーの最小値と最大値を渡している
class MakeViewFactory{
init(slidermaxVal:Float,sliderminPoint:CGPoint,slidermaxPoint:CGPoint,width:CGFloat,height:CGFloat) {
self.sliderMaxValue = slidermaxVal
self.sliderMinPoint = sliderminPoint
self.sliderMaxPoint = slidermaxPoint
print(slidermaxPoint)
//スライダーの最大値を出力
self.width = width
self.height = height
}
・・・中略・・・
}
ここに値を渡すタイミングが悪かった...
機種別のスライダーの CGPoint
- iPhone11 (394.0, 383.0)
- iPhone8 (355.0, 278.5)
print(slidermaxPoint)
でデバックしてみると、
//StoryBoardでiPhone11を設定
(394.0, 383.0)
//この値で描画が行われている
//ここで何が行われているかが鍵
//ViewDidLoad()実行後→iPhone8にSliderViewが変更
(355.0, 278.5)
変更される前にスライダーに値を渡していた。
解決策
ViewDidLoad後にクロージャーを用いて処理が終わった後にmakeViewを行なう- ViewControllerのライフサイクル を意識して適切なところで処理を入れる
ライフサイクルを理解してViewが読み込まれた後にViewを作成してあげると解決した。
ライフサイクル についての記事UIViewControllerのライフサイクルがとても分かりやすかった。
どこでViewが更新されているのか
viewwillLayoutSubviews以降の処理
それぞれのライフサイクル で調べてみた
viewDidLoad→(355.0, 278.5)
viewwillAppear→(355.0, 278.5)
2020-07-18 11:34:13.851786+0900 S Player Plus[26679:11650844] Metal API Validation Enabled
viewwillLayoutSubviews→(355.0, 278.5)
viewwillLayoutSubviews→(355.0, 322.5)
viewdidLayoutSubviews→(394.0, 383.0)
上のコードをみるとviewwillLayoutSubviewsでViewが更新されている。
したがってここに自作Viewを作成してあげると問題が解決します。がviewwillLayoutSubviewsは複数回呼ばれるので注意が必要
//Viewのレイアウト処理 複数回呼ばれる
override func viewWillLayoutSubviews() {}
override func viewDidLayoutSubviews() {}
//レイアウト処理終了後
override func viewDidAppear(_ animated: Bool) {}
最後に
アプリ開発でviewDidLoad()などのメソッドはおまじないのように使っていましたが、今回の問題解決からライフサイクルを意識したコードを書くことができました。
Viewの描画がバグる時は参考にしてみてください!