Storyboardをどこまでどう使うかはクックパッドさんの1Storyboard = 1VCの記事などでも話に上がってますが
もっと細かいところで
UIViewを設置する際
こんな感じでコードで書くか
view.addSubview(hogeView)
だったりxibファイル作って
StoryboardでView設置して紐付けるか
どういう基準で選ぶの?と思っていたのですが状況別でそれとなく理解したのでまとめておきます
Viewが中身しか変化しない場合
xibで作って設置
->中身の変化だけVCでかく
import UIKit
class GirlsView: UIView {
//プロパティは省略
//storyboardで設置した時
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
loadNib()
}
override func awakeFromNib() {
super.awakeFromNib()
//viewのautolayout取得前//VCの制約決定前
}
override func layoutSubviews() {
super.layoutSubviews()
//viewのautolayout取得前後//VCの制約決定前
}
func loadNib() {
//こっちでも
if let view = Bundle(for: type(of: self)).loadNibNamed(String(describing: type(of: self)), owner: self, options: nil)?.first as? UIView {
view.frame = self.bounds
self.addSubview(view)
}
//こっちでもViewのUI表示してくれる //String(describing: type(of: self)) = "GirlsView"
let view = Bundle.main.loadNibNamed("GirlsView", owner: self, options: nil)?.first as! UIView
view.frame = self.bounds
self.addSubview(view)
}
//ぐぐるとこのパターンも結構あった//こちらだとうまく表示できず
private func configure() {
let nib = UINib(nibName: "GirlsView", bundle: nil)
//nibは取得できたが、各要素の取得がダメになるらしい
//Viewの各要素はfile's ownerに紐付けないとダメ?
//File's OwnerのみにGirlsViewを紐付けた状態で繋ぐ->各要素が勝手に親のUIViewではなくFile's Ownerに紐づく
guard let view = nib.instantiate(withOwner: self, options: nil).first as? UIView else { return }
addSubview(view)
}
}
Viewの数を動的に変化させたい場合
Tinderの模擬アプリをYoutube用に作成した時
がこの場合に当たります
Viewの数だけVCで設置するというのは
必要なViewの数が変化した時に対応できないので
雛形だけxibで作っておいて、設置や中身の設定はVCでやるというのが良さそうです
import UIKit
class GirlsView: UIView {
//プロパティは省略
//コードで設置した時
override init(frame: CGRect) {
super.init(frame: frame)
loadNib()
}
override func awakeFromNib() {
super.awakeFromNib()
//viewのautolayout取得前//VCの制約決定前
}
override func layoutSubviews() {
super.layoutSubviews()
//viewのautolayout取得前後//VCの制約決定前
}
func loadNib() {
//こっちでも
if let view = Bundle(for: type(of: self)).loadNibNamed(String(describing: type(of: self)), owner: self, options: nil)?.first as? UIView {
view.frame = self.bounds
self.addSubview(view)
}
//こっちでもViewのUI表示してくれる //String(describing: type(of: self)) = "GirlsView"
let view = Bundle.main.loadNibNamed("GirlsView", owner: self, options: nil)?.first as! UIView
view.frame = self.bounds
self.addSubview(view)
}
//ぐぐるとこのパターンも結構あった//こちらだとうまく表示できず
private func configure() {
let nib = UINib(nibName: "GirlsView", bundle: nil)
//nibは取得できたが、各要素の取得がダメになるらしい
//Viewの各要素はfile's ownerに紐付けないとダメ?
//File's OwnerのみにGirlsViewを紐付けた状態で繋ぐ->各要素が勝手に親のUIViewではなくFile's Ownerに紐づく
guard let view = nib.instantiate(withOwner: self, options: nil).first as? UIView else { return }
addSubview(view)
}
}
ポイント
- xibでcustomViewを生成->コードで配置の場合
->loadNibNamed
でxibを指定->フレームを指定->addSubViewをcustomView内でもやる
このやり方しかうまくViewを表示できませんでした。
->File's Owner
との兼ね合いでこういう結果になったんだと思います。
またわかったら追記します。
- 2つの
init
,awakeFromNib
,layoutSubviews
の違い
->override init(frame: CGRect)
: コードでcustomView設置したとき呼ばれる
->required init?(coder aDecoder: NSCoder)
: storyboardでcustomView設置したとき呼ばれる
->awakeFromNib
: storyboardでcustomView設置したとき、required init
の後に呼ばれる->View要素のframeはAutoLayout適用前の値
->layoutSubviews
: storyboardでcustomView設置したとき(なのかはあとで調べる)、required init
, awakeFromNib
の後に呼ばれる->View要素のframeはAutoLayout適用後の値
最後に
いろんなやり方があると思いますので他の意見や反論あればどしどしお待ちしてます
参考
・init(frame:), init(coder:), awakeFromNib, prepareForInterfaceBuilder が呼ばれる条件をまとめてみた
・[Swift, iOS] awakeFromNibでView要素のframeサイズがおかしい - TERAKOYA
・IB/Storyboard使わない派のlayoutSubviewsによるレイアウト調整 - Qiita
・UIViewControllerのライフサイクル - Qiita
->Viewとは関係ないけど合わせてやっとくと良さそうなので、、、