Hello everyone!
I hope everyone would be doing great.
I googled for a long time but I couldn’t find any good tutorial for Container View, I read a tutorial where two Container Views were stacked over one another to achieve the required task, which is certainly not the proper way to do it.
Anyway, I am going to do a tutorial on Container View. So, Lets get started without wasting any further time.
Create a new project and drag a Container View along with two Buttons over a View Controller.
Drag a View Controller and connect Container View Controller with an Empty Segue to it. After that select the newly added View Controller open the Size Inspector and set the Simulated Size to Freeform and adjust the width and height of the controller according to the Container View Controller.
Resulting (in my case):
Repeat the same step for a second View Controller.
Your Storyboard will more or less look like this:
After that, add three classes of type UIViewController, i.e two for child view controllers(Let’s say FirstViewController.swift and SecondViewController.swift) and one for container view controller(ContainerViewController.swift), also add a class of type UIStoryboardSegue. Add all these classes to View Controllers and Empty Segues on storyboard, respectively.
When done adding classes, give identifiers to Embedded and Empty segues.
Open up your ViewController.swift class, create two action functions of the buttons that you added in the start, and paste the following code inside:
class ViewController: UIViewController { var container: ContainerViewController! override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } @IBAction func segmentControl(_ sender: UISegmentedControl) { if sender.selectedSegmentIndex == 0{ container!.segueIdentifierReceivedFromParent("first") }else{ container!.segueIdentifierReceivedFromParent("second") } } override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue.identifier == "container"{ container = segue.destination as! ContainerViewController //For adding animation to the transition of containerviews you can use container's object property // animationDurationWithOptions and pass in the time duration and transition animation option as a tuple // Animations that can be used // .transitionFlipFromLeft, .transitionFlipFromRight, .transitionCurlUp // .transitionCurlDown, .transitionCrossDissolve, .transitionFlipFromTop container.animationDurationWithOptions = (0.2, .transitionFlipFromBottom) } } }
In your ContainerViewController.swift, paste the following code:
class ContainerViewController: UIViewController { //Manipulating container views fileprivate weak var viewController : UIViewController! //Keeping track of containerViews fileprivate var containerViewObjects = Dictionary<String,UIViewController>() // Pass in a tuple of required TimeInterval with UIViewAnimationOptions var animationDurationWithOptions:(TimeInterval, UIViewAnimationOptions) = (0,[]) // Specifies which ever container view is on the front open var currentViewController : UIViewController{ get { return self.viewController } } fileprivate var segueIdentifier : String! //Identifier For First Container SubView @IBInspectable internal var firstLinkedSubView : String! override open func viewDidLoad() { super.viewDidLoad() } open override func viewDidAppear(_ animated: Bool) { if let identifier = firstLinkedSubView{ segueIdentifierReceivedFromParent(identifier) } } override open func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } func segueIdentifierReceivedFromParent(_ identifier: String){ self.segueIdentifier = identifier self.performSegue(withIdentifier: self.segueIdentifier, sender: nil) } override open func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue.identifier == segueIdentifier{ //Remove Container View if viewController != nil{ viewController.view.removeFromSuperview() viewController = nil } //Add to dictionary if isn't already there if ((self.containerViewObjects[self.segueIdentifier] == nil)){ viewController = segue.destination self.containerViewObjects[self.segueIdentifier] = viewController }else{ for (key, value) in self.containerViewObjects{ if key == self.segueIdentifier{ viewController = value } } } UIView.transition(with: self.view, duration: animationDurationWithOptions.0, options: animationDurationWithOptions.1, animations: { self.addChildViewController(self.viewController) self.viewController.view.frame = CGRect(x: 0,y: 0, width: self.view.frame.width,height: self.view.frame.height) self.view.addSubview(self.viewController.view) }, completion: { (complete) in self.viewController.didMove(toParentViewController: self) }) } } }
And in your Empty Segue class:
class Empty: UIStoryboardSegue{ override func perform() { } }
After that you’re good to go.
Here is a video tutorial for this.
I have uploaded this project on Github for reference.
Cheers!
This article covers some important things you must know when you are considering a move…
What is Unit Testing? In its simplest term, unit testing is testing a small piece…
In this article, you will learn about a type of Creational Design Pattern which is…
In this tutorial, you will go through the use of targets to achieve two separate…
In this article, you will learn about a type of Structural Design Pattern which is…
In this article you will learn about a type of Creational Design Pattern which is…
View Comments
Reblogged this on Dinesh Ram Kali..
Just wondering, is this is the right way to do it ?
I don't know if its the right way because only an official Apple developer can tell that. but what I can tell you is that its the only proper way you would find on internet. :)
Thank you for this great job ! : )
I'm new to Apple-develop and do you have a objective-c sample there?
Hello anon!
I don't have the sample for obj-c but I think I can try and write it for you.
There you go. Here is the link for Objective-C sample code: https://github.com/iaaqib/Container-View-Controller-
Cheers! :)
Hi Aaqib Hussain:
Thank you help me out of the problem, so kind of you ! [handshake] : )
Happy to help. :)
Hi! Thank you for this awesome tutorial. I am new to coding and this has been a great help. I am now trying to figure out how to put some animations between the new and old viewcontrollers, but I can't figure out where to put the code exactly. I've tried in the perform() inside the custom segue based on other sources, but that doesn't seem to work so far and I get several errors like: "Application tried to present modally an active controller". Can you help me with that?
Hi Jeppro, I am sorry for the late reply but I have updated the tutorial and my Github repo with the animation code, kindly check. Thanks. :)
How would you go about this is you wanted to animate the transition in views?
Hi Dave, I am sorry for the late reply but I have updated the tutorial and my github with the animation code kindly check. Thanks. :)
Thank you. It saved my day :)
How can you access elements on the containerViews from the parent?
Like if each container has an array of values I want to obtain from each child containerView?
If you got to the github link. I have added an example to access things. you can look at the sample project. Hope this helps. :)
Great one my friend..
Keep it up ! :)