LoginSignup
9
8

More than 3 years have passed since last update.

UIViewをコードで書くかxibで書くかの話(状況別)[Swift]

Last updated at Posted at 2019-11-29

Storyboardをどこまでどう使うかはクックパッドさんの1Storyboard = 1VCの記事などでも話に上がってますが
もっと細かいところで

UIViewを設置する際
こんな感じでコードで書くか

view.addSubview(hogeView)

だったりxibファイル作って
StoryboardでView設置して紐付けるか

どういう基準で選ぶの?と思っていたのですが状況別でそれとなく理解したのでまとめておきます

Viewが中身しか変化しない場合

xibで作って設置
->中身の変化だけVCでかく

GirlsView.swift
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でやるというのが良さそうです

GirlsView.swift
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とは関係ないけど合わせてやっとくと良さそうなので、、、

9
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
8