iOS Nested View Controllers View Inside Uiviewcontroller's View

iOS Nested View Controllers view inside UIViewController's view?

No, this is generally good design, it helps keep your view controllers concise. However you should be using the view controller containment pattern, take a look at the following documentation.

Implementing a Container View Controller

This is incredibly simple to setup using Interface Builder with Storyboards as well, take a look at the Container View in the object library.

Here is a contrived example in a Storyboard. In this example you would have 4 view controllers, one that holds the 3 containers, and one for each container. When you present the left most controller that has all of the containers, the Storyboard will automatically initialize and embed the other 3. You can access these child view controllers via the childViewControllers property or there is a method you can override prepareForSegue:sender: and capture the destination view controllers of the segue about to be called. This is also a good point to pass properties to the child view controllers if any are needed.

Sample Image

Using Nested ViewControllers, is it possible?

It is possible (and quite popular). Look for "container view controllers". Apple documentation

Nesting view controllers inside a storyboard

View Controller Containment is the way to go. Have a look at Apple's documentation about it:

Creating Custom Container View Controllers

Container view controllers are a critical part of iOS app design. They
allow you to decompose your app into smaller and simpler parts, each
controlled by a view controller dedicated to that task. Containers
allow these view controllers to work together to present a seamless
interface.

You can use it in storyboards as well by using a container view.

Sample Image

Useful tutorial: Storyboards With Custom Container View Controllers

iOS custom navigation with nested view controllers

Apparently, what I was doing was sort of OK according to How to add an UIViewController's view as subview.

Loading a View Controller inside a View In Xcode

Yes you can easily do it by adding the UIViewController view like below..

_viewController=[self.storyboard instantiateViewControllerWithIdentifier:@"ViewController"];
[self.view addSubview:viewController.view];

As soon as you add viewController.view your viewDidLoad method inside ViewController gets called.

Update: As per UIViewController Class Reference you need to add two more steps when adding a UIViewController as subview inside another ViewController.

[self addChildViewController:viewcontroller];
[self.view addSubview:viewController.view];
[viewcontroller didMoveToParentViewController:self];

Above completes the answer.

Hope this helps.
Cheers.

UIViewController Nested View To Screen Edge

Assuming you're using Xcode 6...

There are two things to keep in mind when setting Auto Layout constraints regarding margins:

1. Adding new constraints

Xcode defaults new constraints to include margins. You'll find this on the 'Pin' menu - there's a checkbox that defaults to "Constrain to margins":

Constrain to margins checkbox under 'Pin' menu.

In the above screenshot, the left and right constraints both include margins. Unchecking this box will show the distance in points not including the margins:

Not including margins in the constraints.

2. Removing the margin calculation from an existing constraint.

You can adjust a constraint to not include the margin by selecting the constraint and accessing the Size Inspector (5th icon in right-hand panel, or Command+Option+5) and editing the portion that is relative to the margin. Access the dropdown and unselect the "Relative To Margin" option:

Remove the margin from the constraint.

Note that the constant value itself will stay the same, but the object will adjust and not longer take the margin into consideration.

Lastly, I haven't found a way to turn this behavior off.. I would prefer to not have constraints set against the margins by default, but as far as I am aware with Xcode 6.1.1 there isn't a way to change this behavior.

Adding a view controller as a subview in another view controller

A couple of observations:

  1. When you instantiate the second view controller, you are calling ViewControllerB(). If that view controller programmatically creates its view (which is unusual) that would be fine. But the presence of the IBOutlet suggests that this second view controller's scene was defined in Interface Builder, but by calling ViewControllerB(), you are not giving the storyboard a chance to instantiate that scene and hook up all the outlets. Thus the implicitly unwrapped UILabel is nil, resulting in your error message.

    Instead, you want to give your destination view controller a "storyboard id" in Interface Builder and then you can use instantiateViewController(withIdentifier:) to instantiate it (and hook up all of the IB outlets). In Swift 3:

    let controller = storyboard!.instantiateViewController(withIdentifier: "scene storyboard id")

    You can now access this controller's view.

  2. But if you really want to do addSubview (i.e. you're not transitioning to the next scene), then you are engaging in a practice called "view controller containment". You do not just want to simply addSubview. You want to do some additional container view controller calls, e.g.:

    let controller = storyboard!.instantiateViewController(withIdentifier: "scene storyboard id")
    addChild(controller)
    controller.view.frame = ... // or, better, turn off `translatesAutoresizingMaskIntoConstraints` and then define constraints for this subview
    view.addSubview(controller.view)
    controller.didMove(toParent: self)

    For more information about why this addChild (previously called addChildViewController) and didMove(toParent:) (previously called didMove(toParentViewController:)) are necessary, see WWDC 2011 video #102 - Implementing UIViewController Containment. In short, you need to ensure that your view controller hierarchy stays in sync with your view hierarchy, and these calls to addChild and didMove(toParent:) ensure this is the case.

    Also see Creating Custom Container View Controllers in the View Controller Programming Guide.


By the way, the above illustrates how to do this programmatically. It is actually much easier if you use the "container view" in Interface Builder.

Sample Image

Then you don't have to worry about any of these containment-related calls, and Interface Builder will take care of it for you.

For Swift 2 implementation, see previous revision of this answer.



Related Topics



Leave a reply



Submit