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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
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:
1 2 3 4 5 6 |
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!
16 Comments