ContainerView with multiple embed segues

IosObjective CIos6Segue

Ios Problem Overview


Is there a way to have a single ContainerView with multiple embed segues? The aim is for a ContainerView to hold a few different ViewControllers depending on what buttons have been pressed; only one is going to be visible at a time. I want to use embed segues so that in Interface Builder the storyboards are automatically shown at the same size as the ContainerView.

I realise that I can manually resize the other ViewControllers in InterfaceBuilder, but I want the automatic sizing provided by the embed segue. If another way of doing that is available, that would be fine too. Not having the views load on viewDidLoad is fine - as mentioned earlier, the shown ViewController can change depending on the buttons pressed.

Ios Solutions


Solution 1 - Ios

No, there is no way to have multiple embed segues to one container view. One way to do all the setup in IB, would be to make the embedded controller a UITabBarController (with the tab bar hidden). You can then have as many controllers in the tabs as you want, and switch to them in code using the selectedIndex property of UITabBarController.

Solution 2 - Ios

Yes, I was able to achieve what you're looking for inspired by @rdelmar post. What you need to do is to embed a UITabBarViewController into your container view. Then you programmatically choose which controller you like to present. You might also like to hide the tab bar.

Container view indirectly containing more views

If you want you can also hide the tab bars seen in the storyboard file

You can choose the view controller you want to present by subclassing the UITabBarController:

override func viewDidLoad() {
    super.viewDidLoad()
    self.selectedIndex = 1
}

You can hide the tab bar in your view controller by calling self.tabBarController?.tabBar.isHidden = true in viewDidLoad().

Solution 3 - Ios

I recognize this question is a bit old, but I wanted to answer in case you're still looking or other people find this. I had a similar issue and I worked around it.

In short, you'll have three layers:

  • an external view controller ("ExternalViewController")
  • a view controller manager ("ViewControllerManager")
  • the child view controllers you actually want to be switching between ("ChildViewController")

Use a container view in ExternalViewController with an embed segue to the ViewControllerManager. ViewControllerManager itself would then hold other ChildViewControllers programmatically as described https://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/CreatingCustomContainerViewControllers/CreatingCustomContainerViewControllers.html">in this Apple documentation, specifically the section on adding and removing a child.

When you add a child view controller, set its frame to be the same as the ViewControllerManager's frame (since you're doing this inside the ViewControllerManager, set the child's frame equal to self.view.frame). You will also need some logic and an external control to do the switching inside of ExternalViewController, of course.

Hope this helps!

Solution 4 - Ios

I found this wonderful article that explained exactly how to do it: http://sandmoose.com/post/35714028270/storyboards-with-custom-container-view-controllers

you get your container and can call any view controller behind, there is a bit of set up to have everything linked but once done, you get a still useable storyboard.

Solution 5 - Ios

I've achieved that by making use of -shouldPerformSegueWithIdentifier:sender:. I have a container that is passed an object and depending on the type of this object decides which child view controller to show.

The structure seems a little over complicated but allows the base view controller to ignore the different types of tasks I have, leaving that to the container view controller. The container view controller has then multiple container views which segues are only performed depending on the type of task.

I don't know if you can actually perform the embed segues manually by calling -performSegueWithIdentifier:sender: but that could also be a possibility.

Solution 6 - Ios

I struggled with this for a long time, too. I had the case where I had different, but similar embedded table view controllers that I wanted to show depending on a parameter that was set in the segue to the view controller. What worked was to put in the embedded container with an IBOutlet in the view controller. The container can have size constraints set in IB. However, don't make any embed segues in IB. Then in viewDidLoad, I programmatically add the correct view controller and pin its edges to the embed container.

The heart of this approach is seen in the following code (Swift 4):

extension UIView {
    func pinToParent() {
        self.translatesAutoresizingMaskIntoConstraints = false
        let attributes: [NSLayoutAttribute] = [.top, .bottom, .right, .left]
        NSLayoutConstraint.activate(attributes.map {
            NSLayoutConstraint(item: self, attribute: $0, relatedBy: .equal, toItem: self.superview, attribute: $0, multiplier: 1, constant: 0)
        })
    }
}

class ColorVC: UIViewController {
    
    @IBOutlet weak var tableContainer: UIView!
    var color : rgb = .red
    
    fileprivate var colorTableVC : ColorTableVC?

    override func viewDidLoad() {
        super.viewDidLoad()

        switch color {
        case .red:
            colorTableVC = RedTableVC.init(style: .plain)
        case .green:
            colorTableVC = GreenTableVC.init(style: .plain)
        case .blue:
            colorTableVC = BlueTableVC.init(style: .plain)
        }
        if let vc = colorTableVC {
            if (vc.view) != nil {
                self.addChildViewController(vc)
                tableContainer.addSubview(vc.view)
                vc.view.pinToParent()
                vc.didMove(toParentViewController: self)
            }
        }
    }
}

In the ColorVC, one sees the container IBOutlet and the "color" parameter set by the main table view controller. The RedTableVC, GreenTableVC, and BlueTableVC are all subclassed from ColorTableVC which is sub-classed from UITableViewController. The common heritage lets me use one "colorTableVC" variable to point to any of the instantiated controllers. (Not entirely necessary). But this does avoid duplicating code below to add the view in the heirarchy and pin the new controller to the container view. At the top, I made an extension on UIView to pin a view to its parents edges.

The following image shows how the project and particularly the view controller on the right was set up in IB. For this example, I made the height of the "embedded" controller half the height of the main view controller - so when you rotate the device, one can see that the constraints set in IB are indeed applied.

Embedded controller IB setup

Solution 7 - Ios

In your working viewController drag a uiview and set constraint to top, leading, trailing, bottom to safe area (Iphone X serise).

Now put Container view (Content View) inside that UIView. Put as many content views as you want inside that UIView and embed to respective ViewContrllers.

Worked for me.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSteve HaleyView Question on Stackoverflow
Solution 1 - IosrdelmarView Answer on Stackoverflow
Solution 2 - IosAndrejView Answer on Stackoverflow
Solution 3 - IosUberJasonView Answer on Stackoverflow
Solution 4 - IosKanjiroushiView Answer on Stackoverflow
Solution 5 - IosFábio OliveiraView Answer on Stackoverflow
Solution 6 - IosanorskdevView Answer on Stackoverflow
Solution 7 - IosJobLessView Answer on Stackoverflow