75

Note to googlers, this Q-A is now six years out of date!

As Micky below and others mention, this is now done on an everyday basis with Containers in iOS.


I have a ViewController which controls many subviews. When I click one of the buttons I initialize another viewcontroller and show it's view as the subview of this view. However the subview exceeds the bounds of the frame for subview and infact fills the entire screen.

What could be wrong? I presume the problem is that UIViewController's view has a frame (0,0,320,460) and hence fills the entire screen (though it receive's touch events only when touched within the subview frame bounds). How can I resize the frame to fit as subview.

In short, I need help adding a viewcontroller's view as a subview to another viewcontroller's view.

Thanks!

meaning-matters
  • 18,141
  • 8
  • 65
  • 115
sperumal
  • 759
  • 1
  • 6
  • 3
  • 1
    I would recommend against this. I did this for my first iPhone app and it turned out to be a huge bizarre mess, not to mention the fact that it broke a lot of stuff that I was trying to do with Interface Builder. In the 3.0 docs they specifically say - 1 View Controller per screen. You should do this! – bpapa Sep 28 '09 at 18:42
  • Yeah even I read about it, but the problem is if I put it all in 1 viewcontroller it is whole lot of code into 1, and there are lots of IBOutlets and actions, and tables. Hence for the sake of clarity and modularity I tried to have 2 seperate viewcontrollers, with the second one just supplying view to the main viewcontroller and handling its own events. This way the main viewcontroller is somewhat cleaner. What should I be doing instead. Should I have multiple view controllers with nav controller or 1 huge view controller. – sperumal Sep 30 '09 at 21:54
  • Have a look at this [tutorial](http://blog.jayway.com/2009/03/22/uitoolbars-in-iphone-os-2x/). It only partially works though – Casebash Sep 23 '10 at 00:37

8 Answers8

86

As of iOS 5, Apple now allows you to make custom containers for the purpose of adding a UIViewController to another UIViewController particularly via methods such as addChildViewController so it is indeed possible to nest UIViewControllers

EDIT: Including in-place summary so as to avoid link breakage

I quote:

iOS provides many standard containers to help you organize your apps. However, sometimes you need to create a custom workflow that doesn’t match that provided by any of the system containers. Perhaps in your vision, your app needs a specific organization of child view controllers with specialized navigation gestures or animation transitions between them. To do that, you implement a custom container - Tell me more...

...and:

When you design a container, you create explicit parent-child relationships between your container, the parent, and other view controllers, its children - Tell me more

Sample (courtesy of Apple docs) Adding another view controller’s view to the container’s view hierarchy

- (void) displayContentController: (UIViewController*) content
{
   [self addChildViewController:content];                 
   content.view.frame = [self frameForContentController]; 
   [self.view addSubview:self.currentClientView];
   [content didMoveToParentViewController:self];          
}
Cœur
  • 32,421
  • 21
  • 173
  • 232
MickyD
  • 13,463
  • 6
  • 39
  • 60
41

Thanks to this guys I did it http://highoncoding.com/Articles/848_Creating_iPad_Dashboard_Using_UIViewController_Containment.aspx

Add UIView, connect it to header:

@property (weak, nonatomic) IBOutlet UIView *addViewToAddPlot;

In - (void)viewDidLoad do this:

ViewControllerToAdd *nonSystemsController = [[ViewControllerToAdd alloc] initWithNibName:@"ViewControllerToAdd" bundle:nil];
    nonSystemsController.view.frame = self.addViewToAddPlot.bounds;
    [self.addViewToAddPlot addSubview:nonSystemsController.view];
    [self addChildViewController:nonSystemsController];
    [nonSystemsController didMoveToParentViewController:self];

Enjoy

WIll Cobb
  • 113
  • 9
Naloiko Eugene
  • 2,285
  • 1
  • 25
  • 18
26

This answer is correct for old versions of iOS, but is now obsolete. You should use Micky Duncan's answer, which covers custom containers.

Don't do this! The intent of the UIViewController is to drive the entire screen. It just isn't appropriate for this, and it doesn't really add anything you need.

All you need is an object that owns your custom view. Just use a subclass of UIView itself, so it can be added to your window hierarchy and the memory management is fully automatic.

Point the subview NIB's owner a custom subclass of UIView. Add a contentView outlet to this custom subclass, and point it at the view within the nib. In the custom subclass do something like this:

- (id)initWithFrame: (CGRect)inFrame;
{
    if ( (self = [super initWithFrame: inFrame]) ) {
        [[NSBundle mainBundle] loadNibNamed: @"NibNameHere"
                                      owner: self
                                    options: nil];
        contentView.size = inFrame.size;
        // do extra loading here
        [self addSubview: contentView];
    }
    return self;
}

- (void)dealloc;
{
    self.contentView = nil;
    // additional release here
    [super dealloc];
}

(I'm assuming here you're using initWithFrame: to construct the subview.)

Steven Fisher
  • 43,056
  • 20
  • 131
  • 184
18

I feel like all of these answers are slightly incomplete, so here's the proper way to add a viewController's view as a subview of another viewController's view:

    [self addChildViewController:viewControllerToAdd];
    [self.view addSubview:viewControllerToAdd.view];
    [viewControllerToAdd didMoveToParentViewController:self];

If you'd like, you can copy this into your code as a snippet. SO doesn't seem to understand code replacement formatting, but they will show up clean in Xcode:

    [self addChildViewController:<#viewControllerToAdd#>];
    [self.view addSubview:<#viewControllerToAdd#>.view];
    [<#viewControllerToAdd#> didMoveToParentViewController:self];

willMove is called automatically w/ addChild. Thanks @iOSSergey

When your custom container calls the addChildViewController: method, it automatically calls the willMoveToParentViewController: method of the view controller to be added as a child before adding it.

Logan
  • 49,229
  • 19
  • 92
  • 123
  • When your custom container calls the addChildViewController: method, it automatically calls the willMoveToParentViewController: method of the view controller to be added as a child before adding it. – iOSergey May 14 '16 at 00:40
  • @iOSergey do you have a link to that? Would love to update the answer to be more correct. – Logan May 14 '16 at 01:23
  • I actually always used to use willMoveToParent manually as well, but when I accidentally read apple reference to this function have been surprised :) https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIViewController_Class/#//apple_ref/occ/instm/UIViewController/willMoveToParentViewController: – iOSergey May 14 '16 at 02:59
  • @iOSergey - sorry, maybe I'm being dense, but I am not seeing it on there :) Mind pointing me a bit more specifically! You are not alone in always calling, and I'd like to have a good reference when people inevitably tell me to put it back in! Thanks again! – Logan May 14 '16 at 03:08
  • Search for "willMoveToParentViewController" on the website I linked, expend "willMoveToParentViewController" reference and under Discussion header the last paragraph :) I posted the full link, but for some reason its redirecting to the top. – iOSergey May 14 '16 at 03:17
  • @iOSergey Awesome, I was looking in addChild instead of willMove, duh! Thanks! – Logan May 14 '16 at 03:43
6

Use:

[self.view addSubview:obj.view];
rptwsthi
  • 9,855
  • 10
  • 65
  • 102
rahul gupta
  • 396
  • 3
  • 8
1

Change the frame size of viewcontroller.view.frame, and then add to subview. [viewcontrollerparent.view addSubview:viewcontroller.view]

rptwsthi
  • 9,855
  • 10
  • 65
  • 102
CiNN
  • 9,452
  • 6
  • 40
  • 53
0

You may use PopupController for the same one the SDK which shows UIViewController as subview You may check PopupController

Here is sample code for the same

popup = PopupController
        .create(self.navigationController!)
        .customize(
            [
                .layout(.center),
                .animation(.fadeIn),
                .backgroundStyle(.blackFilter(alpha: 0.8)),
                .dismissWhenTaps(true),
                .scrollable(true)
            ]
        )
        .didShowHandler { popup in
        }
        .didCloseHandler { popup in
    }
    let container = MTMPlayerAndCardSelectionVC.instance()
    container.closeHandler = {() in
        self.popup.dismiss()
    }

    popup.show(container)
Anjali jariwala
  • 360
  • 3
  • 13
0

You must set the bounds properties to fit that frame. frame its superview properties, and bounds limit the frame in the view itself coordinate system.

bolek
  • 41
  • 1