前書き
複雑なレイアウトはカスタムビューの中でやって、UIViewControllerではそれぞれのカスタムビューを配置していくだけ、ということがよくあります。
この時、UIVireControllerにおけるレイアウトは配列させるだけですので、わざわざxibやオートレイアウトを使わずにシンプルにコードでレイアウトしたいことがあると思います。
その際のプラクティスを書き残しておきます。
手順
1、カスタムビューの生成
lazy var tableView : UITableView = self.createTableView()
private func createTableView() -> UITableView {
let view = UITableView()
view.delegate = self
return view
}
カスタムビュー(今回は例のためtableView)をプロパティとしてlazyで宣言します。
lazyにすることで、tableViewが最初に呼ばれた時にcreateTableView()が発火するようになります。
createTableView()にて、カスタムビューのインスタンスを生成し初期化や設定を行いましょう。
注意するのは、ここではまだ位置や大きさのレイアウトをしないということです。
実体の生成にまつわる処理をここに書きます。背景色など、変化することのないプロパティはここに書いても構いません。
2、カスタムビューをviewDidLoadで貼り付け
override func viewDidLoad() {
super.viewDidLoad()
self.view.addSubview(tableView)
}
UIViewControllerにtableViewをviewDidLoad内で貼り付けます。
これによりViewControllerが起動した時に一度だけ呼ばれることになります。
基本的にカスタムビューはここで初めて呼ばれるため、1で記述したcreateTableView()はここで実行される形になります。
注意点はここでも位置や大きさのレイアウトをしないということです。
3、viewDidLayoutSubviewsでレイアウト
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
self.layoutTableView()
}
private func layoutTableView() {
tableView.frame = CGRect(x : 0 , y : 0 , width : self.view.frame.width , height : self.view.frame.height )
}
カスタムビューの位置、大きさのレイアウトはここで初めて行います。
複数のカスタムビューがあるときは、layoutXXXView()という関数を複数作ってそれを並列させる形になります。
何が嬉しいのか
基本的にレイアウトは以上の構成でやっていくのが拡張性が高く、柔軟性も高いです。
というのもこの書き方だといくつか嬉しい点があり、
- カスタムビューごとに処理が分かれて見通しが良くなります。
- 生成時に一回やればいい処理と、再描画が走るたびに行いたい処理に分けることができる。
- viewDidLayoutSubviewsはsubviewに変化があったり画面の向きが変わったりする時に必ず呼ばれるため、レイアウトが担保されます
- viewDidLoadではまだビューが表示されておらず、width等のプロパティに正しくアクセスできないことがありますが、viewDidLayoutSubviewsであればviewが表示された時にも呼ばれるのでそれが担保されます。
- layout系の処理が全てviewDidLayoutSubviewsに集約される構成になる(じゃないとビューを動かしても全てviewDidLayoutSubviewsで初期化されてしまうから)
などがあります。ビューの数が増えてくると、コードで全てレイアウトされていると見通しが悪くなるということもあるかもしれません。個人的には3〜4つくらいのカスタムビューで構成されているのが理想です。それ以上増えそうなのであれば、それは別でカスタムビューに切り出す要件のように思います。
以上です。ありがとうございました。