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
:
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 withaddSubview
(and also set theframe
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:
- 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.- 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.- Add any constraints for managing the size and position of the child’s root view.
- 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
I Get Conflicting Provisioning Settings Error When I Try to Archive to Submit an iOS App
Add Swipe to Delete Uitableviewcell
Linking Objective-C Categories in a Static Library
Default Tab Bar Item Colors Using Swift Xcode 6
How to Add Iphonex Launch Image
iOS 7.1 Uitextview Still Not Scrolling to Cursor/Caret After New Line
Rotate a Uiview Around Its Center But Several Times
Swiftui Withanimation Completion Callback
How to Pass Data from One Container to Another, Both Embedded in the Same Uiviewcontroller in Swift
Maskstobounds VS. Clipstobounds
How to Bring Application to Foreground in iOS
Images Can't Contain Alpha Channels or Transparencies
How to Draw Border Around a Uilabel