How to add an UIViewController's view as subview
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!
Solution 1:
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];
}
Solution 2:
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
Solution 3:
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.)
Solution 4:
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.