LoginSignup
4
3

More than 3 years have passed since last update.

小さなViewControllerで画面を組み立てる

Posted at

ViewではなくViewControllerで画面部品を細かく分けて画面を組み立てるサンプルです。
下にToolbarがあり、それ以外はWebViewという簡単な画面です。

簡単な内容ですが、2つ罠に嵌ってしまったため、誰かの助けになることを期待して情報を残しておきます。

WebViewとToolbarの画面

WebViewController

画面表示以外のコードがありません。
外からURLを指定して読み込む機能などは、必要な場合各自追加をお願いします🙇‍♂️

WebViewController.swift
import UIKit
import WebKit

class WebViewController: UIViewController {

    var webView: WKWebView!

    override func loadView() {
        let configuration = WKWebViewConfiguration()
        webView = WKWebView(frame: .zero, configuration: configuration)
        view = webView
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        let url = URL(string: "https://google.com")!
        let request = URLRequest(url: url)
        webView.load(request)
    }

}

ToolbarViewController

こちらも画面表示以外のコードがありません。

ToolbarViewController.swift
import UIKit

class ToolbarViewController: UIViewController {

    var toolbar: UIToolbar!

    override func loadView() {
        toolbar = UIToolbar(frame: .zero)
        let back = UIBarButtonItem(title: "back", style: .plain, target: nil, action: nil)
        toolbar.items = [back]
        view = toolbar
    }
}

画面を組み立てる

import UIKit

class ViewController: UIViewController {

    let toolbar = ToolbarViewController()
    let webView = WebViewController()

    override func loadView() {
        view = UIView(frame: .zero)

        webView.view.translatesAutoresizingMaskIntoConstraints = false
        addChild(webView)
        view.addSubview(webView.view)
        webView.didMove(toParent: self)

        toolbar.view.translatesAutoresizingMaskIntoConstraints = false
        addChild(toolbar)
        view.addSubview(toolbar.view)
        toolbar.didMove(toParent: self)

        let guide = view.safeAreaLayoutGuide
        NSLayoutConstraint.activate([
            webView.view.topAnchor.constraint(equalTo: view.topAnchor),
            webView.view.leftAnchor.constraint(equalTo: view.leftAnchor),
            webView.view.bottomAnchor.constraint(equalTo: toolbar.view.topAnchor),
            webView.view.rightAnchor.constraint(equalTo: view.rightAnchor),
            toolbar.view.leftAnchor.constraint(equalTo: view.leftAnchor),
            toolbar.view.bottomAnchor.constraint(equalTo: guide.bottomAnchor),
            toolbar.view.rightAnchor.constraint(equalTo: view.rightAnchor)
            ])
    }

}

あまり難しい箇所もなくできました!

小さなViewControllerは、Viewが1個ならAutoLayoutのコードを書く必要もないです。
2,3個に押さえて入れ子にすれば、AutoLayoutのコードは短くわかりやすい範囲に収まります。

そのためxibを使わなくても書きやすくなる場合が多いです。
(逆にVCの数だけxibが増殖すると、管理がちょっと面倒かも)

注意点

viewに直接UIToolbarを設定すること

var UIViewController.view に直接UIToolbarを設定してください。
以下のようにUIViewの中にUIToolbarをaddSubviewしてはいけません。

    override func loadView() {
        view = UIView(frame: .zero)

        toolbar = UIToolbar(frame: .zero)
        toolbar.translatesAutoresizingMaskIntoConstraints = false
        let back = UIBarButtonItem(title: "back", style: .plain, target: nil, action: nil)
        toolbar.items = [back]
        view.addSubview(toolbar)

        NSLayoutConstraint.activate([
            toolbar.topAnchor.constraint(equalTo: view.topAnchor),
            toolbar.leftAnchor.constraint(equalTo: view.leftAnchor),
            toolbar.bottomAnchor.constraint(equalTo: view.bottomAnchor),
            toolbar.rightAnchor.constraint(equalTo: view.rightAnchor)
            ])
    }

UIViewの中のUIToolbarを入れる構成では ToolbarのSafe Area対応が機能しません!
以下のような表示になってしまいます。

Safe Areaが想定どおり動いてくれない

UIViewControllerの中で self.view.translatesAutoresizingMaskIntoConstraints = false しない

上記サンプルの例であれば、WebViewControllerのloadView()
self.view.translatesAutoresizingMaskIntoConstraints = false
しても期待通りに動作します。

しかしそれをした場合 WebViewControllerをモーダル表示すると正しく表示されません!
おそらくモーダル表示では、Auto Resizing Maskの自動変換が動作する前提となっているのでしょう。

Toolbarなら問題ないですが(さすがにモーダル表示しないでしょう)
統一しておけば迷うこともないので、UIViewControllerを生成した側が外から
vc.view.translatesAutoresizingMaskIntoConstraints = false
をしましょう。

4
3
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
4
3