iOS — Correct ways to add multiple view controllers on screen at once
While working with iOS application, there are times that when you want to embed multiple ViewControllers into one ViewControllers to display them on a single screen. It is considered as Container View Controller.
UIKit also provides some Container View Controller (E.g: UINavigationViewController, UISplitViewController, UITabBarController). They facilitate navigation between different parts of your user interface.
As an example, we will work on a simple app that show a list of topics and the sentences in the UICollectionView and UITableView. I like to use Reusability when building my apps. It is easy to re-use the parts of screen in other places of our app.
For this example, we divide the UIController(HomeViewController) with the use of ContainerView in 2 parts:
1. TopicsCollectionViewController
2. SentencesTableViewController
Now, the HomeViewController consists of two childViewControllers (TopicsCollectionViewController, SentencesTableViewController)
There are 2 ways to setup ContainerView in iOS app.
1. Programmatically
Firstly, create two UIViews and its outlets in the HomeViewController.
Example: green view is topicsViewContainer, orange view is sentencesViewContainer.
Secondly, add the childViewController to these containerViews. It takes 4 steps to add each childViewController to HomeViewController
1. Call addChild()
on your parent view controller, passing in your child.
2. Set the child’s frame to whatever you need, if you’re using frames.
3. Add the child’s view to your main view, along with any Auto Layout constraints.
4. Call didMove(toParent:)
on the child, passing in your main view controller.
Let try to add the childViewController in viewDidLoad()
and see what happens:
You will see that the frame of subViewController is not fit to the frame of containerView.
The problem is that you are setting the frame in viewDidLoad()
. At this time the geometry of your view is not set and the results will be unpredictable. The frames are not set until its views are laid out.
The question is that, is it possible to add this behavior to the viewDidAppear()
or viewWillLayoutSubviews()
to resolve this issue? The answer is YES. But another issue is occured. Because the viewDidAppear()
or viewWillLayoutSubviews()
is invoked whenever the UIViewController appears or changing in layout.
The best way to add subview to an UIView is using AutoLayout constraints:
2. Using Interface Builder in Storyboard
In my opinion, this is the best way to embed a ChildViewController to a view in ParentViewController. We don’t need to be worried about the subView frame.
1. Instead using normal UIView, we use a ContainerView.
2. Ctrl + Drag from ContainerView to the TopicsCollectionViewController. Then select “Embed”
Do the same for the SentencesTableViewController. The result will be:
Run the application, it works.
As you can see, implementation of ContainerView using Interface Builder is much better, much cleaner than programmatically.