コードで作るContainer View Controller


はじめに

この記事の目的は、コードから、Container View Controllerを作れるようになることです。
子ViewControllerが一つである単純な例で説明を行います。
参考文献の書籍の内容です。

Container View Controllerとは

UINavigationControllerやUITabBarControllerなどといった、ViewControllerヒエラルキーの親子関係の親になり、子ViewControllerのviewを表示するViewControllerのことです。

androidだとFragmentを持つActivityのようなものです。

方法

UIViewControllerでは、子ViewControllerを格納するためのchildrenプロパティが用意されていますが、プロパティを直接扱うことは非推奨です。
childrenプロパティに子ViewControllerを格納するには決まったお作法があり、技術書によれば、作法を破ると手痛い仕打ち(バグ)を受けるとのこと。
つまり、Container View Controllerの作成は、このお作法に則って行う必要があります。

お作法

add 子ViewController

  1. 親になるView Controller(以降親VCと呼称)のaddChild(_:)をコール。引数は子ViewController(以降子VCと呼称)。
  2. 親VCのview.addSubview(_:)によって、子VCのviewを加える。
  3. 子VCのdidMove(toParent:)を引数親VCでコール。

※1. 子VCが親VCのchildrenに格納されるだけでなく、自動で子VCのwillMove(toParant:)が引数親VCで呼ばれる。

remove 子ViewController

本記事の例では扱いませんが、一応removeも。
1. 子VCのwillMove(toParent:)を引数nilでコール。
2. 子VCのviewを親VCのviewから除外する。
3. 子VCのremoveFromParent()をコール。

※3. 子VCがchildrenから除外されるだけでなく、自動で子VCのdidMove(toParant:)が引数nilで呼ばれる。

具体例

子としてPageViewControllerを持つcontaner view controllerを作成します。
初期画面のボタンを押すと、contaner view controllerに遷移するようにしました。

初期ViewController.swift
// buttonのタッチイベントアクション
    @IBAction func onButton(_ sender: UIButton) {
        // 親vc(contaner view controller)と子vcの作成
        let pvc = UIViewController()
        let cvc = MyPageViewController()// 前もって作成済みのもの。ペラペラめくれます。

        // 色を分けて見やすく
        pvc.view.backgroundColor = .white
        cvc.view.backgroundColor = .blue

        // addのお作法
        // 1
        pvc.addChild(cvc)
        // 2
        cvc.view.translatesAutoresizingMaskIntoConstraints = false
        pvc.view.addSubview(cvc.view)
        NSLayoutConstraint.activate([// 親vcの下半分に子vcを表示してみる
            cvc.view.leadingAnchor.constraint(equalTo: pvc.view.leadingAnchor),
            cvc.view.trailingAnchor.constraint(equalTo: pvc.view.trailingAnchor),
            cvc.view.bottomAnchor.constraint(equalTo: pvc.view.bottomAnchor),
            cvc.view.heightAnchor.constraint(equalTo: pvc.view.heightAnchor, multiplier: 0.5)
        ])
        // 3
        cvc.didMove(toParent: pvc)

        present(pvc, animated: true)
    }

Videotogif.gif

参考文献

より詳しくはこちら。

再利用可能なContainer View Controllerはこちらの記事が良さげでした。