【swift】カスタムビューをxibで作成して各ViewControllerで使い回す


概要

StoryboardでViewControllerのViewの一部が他のViewControllerでも同じレイアウトで表示している場合があります。その場合ViewをコピーしてViewControllerに貼り付けて利用したりしますが、それだとそのViewに変更を加えると複数利用しているため他のViewも変更しなくてはなりません。
そう行った場合、使い回せるViewをカスタムビューとしてxibで作成して利用することで、そのxibのみを変更すれば複数のViewでその変更が反映されるようになります。

実装方法

まずは、カスタムビューをxibで作成します。


続いて、ViewControllerで、xibのカスタムビューをインスタンス化します。

ViewController.swift
class ViewController: UIViewController {

    weak var sampleView: UIView!

    override func loadView() {
        super.loadView()

        sampleView = UINib(nibName: "SampleView", bundle: Bundle.main).instantiate(withOwner: self, options: nil).first as? UIView
        sampleView.backgroundColor = .yellow
        view.addSubview(sampleView)
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        sampleView.frame = CGRect.init(x: 100.0, y: 100.0, width: 100.0, height: 100.0)
    }

}

この時に、withOwnerでselfを指定しているので、xibで生成したlabelを@IBOutletで繋ぐことが出来ます。

UINib(nibName: "SampleView", bundle: Bundle.main).instantiate(withOwner: self, options: nil).first as? UIView
ViewController.swift
    weak var sampleView: UIView!
    @IBOutlet weak var label: UILabel!

    override func loadView() {
        super.loadView()

        sampleView = UINib(nibName: "SampleView", bundle: Bundle.main).instantiate(withOwner: self, options: nil).first as? UIView
        sampleView.backgroundColor = .yellow
        view.addSubview(sampleView)
        label.text = "あああ"
    }

■ビルド実行

カスタムビューを管理するクラスを生成する

ViewControllerでxibのViewをインスタンス化して使用するのは上記の方法ですが、多くの場合カスタムビューを管理するクラスを作成してxibとセットで利用したいと考えます。

その方法としては、withOwnerをカスタムビューを管理するクラスにします。

(SampleViewOwnerはSampleView.xibを管理するクラス)

SampleViewOwner.swift
class SampleViewOwner: NSObject {

    @IBOutlet weak var label: UILabel!
    var sampleView: UIView!

    override init() {
        super.init()

        sampleView = UINib(nibName: "SampleView", bundle: Bundle.main).instantiate(withOwner: self, options: nil).first as? UIView
        label.text = "いいい"
    }
}
ViewController.swift
class ViewController: UIViewController {

    var sampleViewOwner: SampleViewOwner!

    override func loadView() {
        super.loadView()

        sampleViewOwner = SampleViewOwner()
        sampleViewOwner.sampleView.backgroundColor = .yellow
        view.addSubview(sampleViewOwner.sampleView)
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        sampleViewOwner.sampleView.frame = CGRect.init(x: 100.0, y: 100.0, width: 100.0, height: 100.0)
    }

}

こうすることで各ViewControllerでownerクラスをインスタンス化して使用すれば、xib上のlabel等の変更は、管理するownerクラスの方で行うことが出来ます。

■ビルド結果