1. ホーム
  2. ios

[解決済み] コンテナビューをプログラム的に追加する方法

2022-06-13 17:59:52

質問

コンテナビューは、インターフェイスエディタで簡単にストーリーボードに追加することができます。追加されたコンテナビューは、プレースホルダビュー、エンベッドセグエ、(子)ビューコントローラーから構成されています。

しかし、コンテナビューをプログラム的に追加する方法を見つけることができません。実際、私は UIContainerView という名前のクラスさえ見つけることができません。

コンテナビューのクラスの名前は、確かに良いスタートです。セグエを含む完全なガイドが大いに評価されるでしょう。

View Controller Programming Guideは知っていますが、Interface BuilderがContainer Viewerに対して行っている方法と同じとは思えません。例えば、制約が適切に設定されている場合、(子)ビューはコンテナビューのサイズ変更に適応することになります。

どのように解決するのですか?

ストーリーボードのコンテナビューは、単に標準的な UIView オブジェクトです。特別な"コンテナビュー"のタイプはありません。実際、ビュー階層を見ると、"コンテナビュー" は標準の UIView :

プログラム的にこれを実現するために、"ビューコントローラーコンテナメント"を使用します。

  • 子ビューコントローラのインスタンスを作成するために instantiateViewController(withIdentifier:) を呼び出して、子ビューコントローラをインスタンス化します。
  • コール addChild を親ビューコントローラで呼び出します。
  • ビューコントローラの view をビュー階層に追加します。 addSubview を設定します (さらに frame や制約を適切に設定します)。
  • を呼び出す。 didMove(toParent:) メソッドを呼び出し、親ビューコントローラへの参照を渡します。

参照 コンテナ型ビューコントローラの実装 の中で ビューコントローラ プログラミングガイド の「コンテナ・ビューコントローラの実装」セクションを参照してください。 UIViewController クラスリファレンス .


例えば、Swift 4.2では、次のようになります。

override func viewDidLoad() {
    super.viewDidLoad()

    let controller = storyboard!.instantiateViewController(withIdentifier: "Second")
    addChild(controller)
    controller.view.translatesAutoresizingMaskIntoConstraints = false
    view.addSubview(controller.view)

    NSLayoutConstraint.activate([
        controller.view.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 10),
        controller.view.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -10),
        controller.view.topAnchor.constraint(equalTo: view.topAnchor, constant: 10),
        controller.view.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -10)
    ])

    controller.didMove(toParent: self)
}

注意:上記は実際に階層に "コンテナビュー" を追加しているわけではありません。もしそれをしたいのであれば、次のようなことをすることになります。

override func viewDidLoad() {
    super.viewDidLoad()

    // add container

    let containerView = UIView()
    containerView.translatesAutoresizingMaskIntoConstraints = false
    view.addSubview(containerView)
    NSLayoutConstraint.activate([
        containerView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 10),
        containerView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -10),
        containerView.topAnchor.constraint(equalTo: view.topAnchor, constant: 10),
        containerView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -10),
    ])

    // add child view controller view to container

    let controller = storyboard!.instantiateViewController(withIdentifier: "Second")
    addChild(controller)
    controller.view.translatesAutoresizingMaskIntoConstraints = false
    containerView.addSubview(controller.view)

    NSLayoutConstraint.activate([
        controller.view.leadingAnchor.constraint(equalTo: containerView.leadingAnchor),
        controller.view.trailingAnchor.constraint(equalTo: containerView.trailingAnchor),
        controller.view.topAnchor.constraint(equalTo: containerView.topAnchor),
        controller.view.bottomAnchor.constraint(equalTo: containerView.bottomAnchor)
    ])

    controller.didMove(toParent: self)
}

この後者のパターンは、異なる子ビューコントローラ間で移行することがあり、1つの子ビューが前の子ビューと同じ場所にあることを確認したい場合に非常に便利です(すなわち、配置のためのすべての固有の制約は、これらの制約を毎回再構築する必要がなく、コンテナビューによって決定されます)。しかし、単に単純なビューの格納を実行する場合、この個別のコンテナビューの必要性はあまり説得力がありません。


上記の例では translatesAutosizingMaskIntoConstraints から false に変更し、自分で制約を定義しています。明らかに translatesAutosizingMaskIntoConstraints として true を設定し frame autosizingMask を追加してください。


については、この回答の以前のリビジョンを参照してください。 スウィフト 3 スウィフト2 のレンダリングです。