How to Add a Container View Programmatically

How to add a Container View programmatically

A storyboard "container view" is just a standard UIView object. There is no special "container view" type. In fact, if you look at the view hierarchy, you can see that the "container view" is a standard UIView:

container view

To achieve this programmatically, you employ "view controller containment":

  • Instantiate the child view controller by calling instantiateViewController(withIdentifier:) on the storyboard object.
  • Call addChild in your parent view controller.
  • Add the view controller's view to your view hierarchy with addSubview (and also set the frame or constraints as appropriate).
  • Call the didMove(toParent:) method on the child view controller, passing the reference to the parent view controller.

See Implementing a Container View Controller in the View Controller Programming Guide and the "Implementing a Container View Controller" section of the UIViewController Class Reference.


For example, in Swift 4.2 it might look like:

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)
}

Note, the above doesn't actually add a "container view" to the hierarchy. If you want to do that, you'd do something like:

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)
}

This latter pattern is extremely useful if ever transitioning between different child view controllers and you just want to make sure one child's view is in the same location and the previous child's view (i.e. all the unique constraints for the placement are dictated by the container view, rather than needing to rebuild these constraints each time). But if just performing simple view containment, the need for this separate container view is less compelling.


In the examples above, I’m setting translatesAutosizingMaskIntoConstraints to false defining the constraints myself. You obviously can leave translatesAutosizingMaskIntoConstraints as true and set both the frame and the autosizingMask for the views you add, if you’d prefer.


See previous revisions of this answer for Swift 3 and Swift 2 renditions.

Loading a UIViewController into a Container View programmatically

Make sure this @IBOutlet var customContainer: UIView! is linked to the containerview and not to the vc's main view in storyboard

How to use container view programmatically

You need to set the frame and/or constraints on the loaded view:

override func viewDidLoad() {
super.viewDidLoad()

setUpViews()

let secondViewController = SecondViewController()

secondViewController.willMove(toParent: self)

containerView.addSubview(secondViewController.view)

// set the frame
secondViewController.view.frame = containerView.bounds

// enable auto-sizing (for example, if the device is rotated)
secondViewController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]

self.addChild(secondViewController)
secondViewController.didMove(toParent: self)

}

How to add a ViewController in containerView programmatically?

You need to first add constraints with parent view and container view, then you also need to add constraints to your container controller. Finally you should add the didMoveToParent in the end of setting all the constraints.

The example is as follows, you can do a similar thing in your case.

 NSLayoutConstraint.activateConstraints([
containerView.leadingAnchor.constraintEqualToAnchor(view.leadingAnchor, constant: 10),
containerView.trailingAnchor.constraintEqualToAnchor(view.trailingAnchor, constant: -10),
containerView.topAnchor.constraintEqualToAnchor(view.topAnchor, constant: 10),
containerView.bottomAnchor.constraintEqualToAnchor(view.bottomAnchor, constant: -10),
])
NSLayoutConstraint.activateConstraints([
controller.view.leadingAnchor.constraintEqualToAnchor(containerView.leadingAnchor),
controller.view.trailingAnchor.constraintEqualToAnchor(containerView.trailingAnchor),
controller.view.topAnchor.constraintEqualToAnchor(containerView.topAnchor),
controller.view.bottomAnchor.constraintEqualToAnchor(containerView.bottomAnchor)
])
controller.didMoveToParentViewController(self)

or you can also refer this: https://codedump.io/share/jVuaGlB85VtK/1/how-to-add-a-container-view-programmatically

Container View Controller Programmatically

Basically this involves having 1 Parent View Controller who'll orchestrate the appearance of his child view controllers.

To be honest, I find the Apple Docs quite complete on this part.

Quote from the same docs :

Adding a Child View Controller to Your Content

To incorporate a child view controller into your content programmatically, create a parent-child relationship between the relevant view controllers by doing the following:

  1. Call the addChildViewController: method of your container view controller.
    This method tells UIKit that your container view controller is now managing the view of the child view controller.
  2. Add the child’s root view to your container’s view hierarchy.
    Always remember to set the size and position of the child’s frame as part of this process.
  3. Add any constraints for managing the size and position of the child’s root view.
  4. Call the didMoveToParentViewController: method of the child view controller.

Codesample :

- (void) displayContentController: (UIViewController*) content {
[self addChildViewController:content];
content.view.frame = [self frameForContentController];
[self.view addSubview:self.currentClientView];
[content didMoveToParentViewController:self];
}

Responding to update about best practices :

Objc.io has some pretty neat articles in this regard.

For example, the article talking about View Controller Containment notes :

View controllers should be reusable and self-contained entities.

Child view controllers are no exception to this rule of thumb. In
order to achieve this, the parent view controller should only be
concerned with two tasks: laying out the child view controller’s root
view, and communicating with the child view controller through its
exposed API. It should never modify the child’s view tree or other
internal state directly.

Child view controllers should contain the necessary logic to manage their view trees themselves – don’t treat them as dumb views. This will result in a clearer separation of concerns and better reusability.

They also talk about transitions between view controllers while using this pattern.

Adding subviews programmatically in presented view controller

Value of containerView.frame inside viewDidLoad is inaccurate Implement

var chart_axes:ChartAxes!

override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
chart_axes.frame = containerView.frame
}

OR set constraints in place

let chart_axes = ChartAxes(frame: containerView.frame)
chart_axes.backgroundColor = UIColor.red.withAlphaComponent(0.6)
containerView.addSubview(chart_axes)
chart_axes.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
chart_axes.leadingAnchor.constraint(equalTo: containerView.leadingAnchor),
chart_axes.trailingAnchor.constraint(equalTo: containerView.trailingAnchor),
chart_axes.topAnchor.constraint(equalTo: containerView.topAnchor),
chart_axes.bottomAnchor.constraint(equalTo: containerView.bottomAnchor)
])

Adding a container view programmatically without storyboard?

You are setting the constraints incorrectly.

You need to first add constraints with parent view and container view, then you also need to add constraints to your container controller.
Finally you should add the didMoveToParent in the end of setting all the constraints.

The example is as follows, you can do a similar thing in your case.

   NSLayoutConstraint.activateConstraints([
containerView.leadingAnchor.constraintEqualToAnchor(view.leadingAnchor, constant: 10),
containerView.trailingAnchor.constraintEqualToAnchor(view.trailingAnchor, constant: -10),
containerView.topAnchor.constraintEqualToAnchor(view.topAnchor, constant: 10),
containerView.bottomAnchor.constraintEqualToAnchor(view.bottomAnchor, constant: -10),
])

NSLayoutConstraint.activateConstraints([
controller.view.leadingAnchor.constraintEqualToAnchor(containerView.leadingAnchor),
controller.view.trailingAnchor.constraintEqualToAnchor(containerView.trailingAnchor),
controller.view.topAnchor.constraintEqualToAnchor(containerView.topAnchor),
controller.view.bottomAnchor.constraintEqualToAnchor(containerView.bottomAnchor)
])

controller.didMoveToParentViewController(self)

Use autolayout to set dynamic UIView to match container view



Related Topics



Leave a reply



Submit