Container View Controllers, Parent View Controllers and Child View Controllers in Xcode (iOS 5 onwards)
For this demo you'll need to
1) create a New Project in Xcode called AddChildViewControllers
2) add two new pairs of files, which will be subclasses of UIViewController (using File->New->File, selecting Objective-C class as a file type, and entering UIViewController in the "Subclass of" box)
-(void)willMoveToParentViewController:(UIViewController *)parent
-(void)didMoveToParentViewController:(UIViewController *)parent
-(void)didMoveToParentViewController:(UIViewController *)parent
4) The first method of the FirstChildViewController:
-(void)willMoveToParentViewController:(UIViewController *)parent
will be called from AddChildViewControllersViewController.m once you've instantiated the new view controller with
FirstChildVC = [[FirstChildViewController alloc] init];
remembering first to import the class with:
#import "FirstChildViewController.h"
and then added the child to your container view controller with the method:
[self addChildViewController:FirstChildVC];
5) The second child method of the First ChildViewController class:
-(void)didMoveToParentViewController:(UIViewController *)parent
needs to be called from AddChildViewControllersViewController.m manually like this
[FirstChildVC didMoveToParentViewController:self];
6) Exactly the same is true of the SecondChildViewController and how the AddChildViewControllersViewController class interacts with it.
7) So, let's make the children do stuff now by inserting stuff into their new child methods. In FirstChildViewController.m we'll put
-(void)willMoveToParentViewController:(UIViewController *)parent
{
NSLog(@"FirstViewController moving to or from parent view controller");
self.view.backgroundColor=[UIColor blueColor];
}
-(void)didMoveToParentViewController:(UIViewController *)parent
{
NSLog(@"FirstViewController did move to parent view controller");
self.view.frame = CGRectMake(0,0,768, 1024);
}
{
NSLog(@"FirstViewController moving to or from parent view controller");
self.view.backgroundColor=[UIColor blueColor];
}
-(void)didMoveToParentViewController:(UIViewController *)parent
{
NSLog(@"FirstViewController did move to parent view controller");
self.view.frame = CGRectMake(0,0,768, 1024);
}
In SecondChildViewController.m we'll put
-(void)willMoveToParentViewController:(UIViewController *)parent
{
NSLog(@"SecondViewController moving to or from parent view controller");
self.view.backgroundColor=[UIColor yellowColor];
}
-(void)didMoveToParentViewController:(UIViewController *)parent
{
NSLog(@"SecondViewController did move to parent view controller");
self.view.frame = CGRectMake(0,0, 1024,768);
}
{
NSLog(@"SecondViewController moving to or from parent view controller");
self.view.backgroundColor=[UIColor yellowColor];
}
-(void)didMoveToParentViewController:(UIViewController *)parent
{
NSLog(@"SecondViewController did move to parent view controller");
self.view.frame = CGRectMake(0,0, 1024,768);
}
Notice we're not defining the frame until the child view controller is added to the parent.
8) Now we instantiate and add the two child view controllers in the viewDidLoad method:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
FirstChildVC = [[FirstChildViewController alloc] init];
[self addChildViewController:FirstChildVC];
[FirstChildVC didMoveToParentViewController:self];
[self.view addSubview:FirstChildVC.view];
SecondChildVC = [[SecondChildViewController alloc] init];
[self addChildViewController:SecondChildVC];
[SecondChildVC didMoveToParentViewController:self];
}
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
FirstChildVC = [[FirstChildViewController alloc] init];
[self addChildViewController:FirstChildVC];
[FirstChildVC didMoveToParentViewController:self];
[self.view addSubview:FirstChildVC.view];
SecondChildVC = [[SecondChildViewController alloc] init];
[self addChildViewController:SecondChildVC];
[SecondChildVC didMoveToParentViewController:self];
}
9) If you look at the console when you run the demo you will notice when the child is added or removed the didMoveToParentViewController: method is called.
10) Finally we add the "doing" code to switch between the two view controllers on an orientation change in AddChildViewControllerViewController.m file:
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
if(UIInterfaceOrientationIsPortrait(fromInterfaceOrientation)) {[self transitionFromViewController:FirstChildVC toViewController:SecondChildVC duration:0.5 options:UIViewAnimationOptionTransitionCrossDissolve animations:nil completion:nil];
[FirstChildVC didMoveToParentViewController:self];}
if(UIInterfaceOrientationIsLandscape(fromInterfaceOrientation)) {[self transitionFromViewController:SecondChildVC toViewController:FirstChildVC duration:0.5 options:UIViewAnimationOptionTransitionCrossDissolve animations:nil completion:nil];
[SecondChildVC didMoveToParentViewController:self];}
}
if(UIInterfaceOrientationIsPortrait(fromInterfaceOrientation)) {[self transitionFromViewController:FirstChildVC toViewController:SecondChildVC duration:0.5 options:UIViewAnimationOptionTransitionCrossDissolve animations:nil completion:nil];
[FirstChildVC didMoveToParentViewController:self];}
if(UIInterfaceOrientationIsLandscape(fromInterfaceOrientation)) {[self transitionFromViewController:SecondChildVC toViewController:FirstChildVC duration:0.5 options:UIViewAnimationOptionTransitionCrossDissolve animations:nil completion:nil];
[SecondChildVC didMoveToParentViewController:self];}
}
11) Note how the child view controller transition method
transitionFromViewController:SecondChildVC toViewController:FirstChildVC duration:0.5 options:UIViewAnimationOptionTransitionCrossDissolve animations:nil completion:nil
doesn't require us to add the view from the new view controller to our self.view manually, it handles all of this.
12) That's it we've created a container view controller and made it transition between the views borrowed from two child view controllers, and we're now ready to run the app.
Update
This post was written quite some time and I realise looking back over it that perhaps too much was implied and not necessarily obvious, so I'm going to place the entire code here in the hope of answering some questions.
First, we'll create the initial view controller (I've named this ContainerViewViewController).
Next we'll create the first child view controller (called here FirstChildViewController).
As long as you know how to create a project file and subsequent UIViewController subclass files, you should be able to copy and paste this code then build and run it on a device. Next turn the device and you should see the screen change colour.
First, we'll create the initial view controller (I've named this ContainerViewViewController).
ContainerViewViewController.m
#import "ContainerViewViewController.h"
#import "FirstChildViewController.h"
#import "SecondChildViewController.h"
@interface ContainerViewViewController ()
@end
@implementation ContainerViewViewController
FirstChildViewController *FirstChildVC;
SecondChildViewController *SecondChildVC;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
FirstChildVC = [[FirstChildViewController alloc] init];
[self addChildViewController:FirstChildVC];
[FirstChildVC didMoveToParentViewController:self];
[self.view addSubview:FirstChildVC.view];
SecondChildVC = [[SecondChildViewController alloc] init];
[self addChildViewController:SecondChildVC];
[SecondChildVC didMoveToParentViewController:self];
}
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
if(UIInterfaceOrientationIsPortrait(fromInterfaceOrientation)) {[self transitionFromViewController:FirstChildVC toViewController:SecondChildVC duration:0.5 options:UIViewAnimationOptionTransitionCrossDissolve animations:nil completion:nil];
[FirstChildVC didMoveToParentViewController:self];}
if(UIInterfaceOrientationIsLandscape(fromInterfaceOrientation)) {[self transitionFromViewController:SecondChildVC toViewController:FirstChildVC duration:0.5 options:UIViewAnimationOptionTransitionCrossDissolve animations:nil completion:nil];
[SecondChildVC didMoveToParentViewController:self];}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
#import "FirstChildViewController.h"
#import "SecondChildViewController.h"
@interface ContainerViewViewController ()
@end
@implementation ContainerViewViewController
FirstChildViewController *FirstChildVC;
SecondChildViewController *SecondChildVC;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
FirstChildVC = [[FirstChildViewController alloc] init];
[self addChildViewController:FirstChildVC];
[FirstChildVC didMoveToParentViewController:self];
[self.view addSubview:FirstChildVC.view];
SecondChildVC = [[SecondChildViewController alloc] init];
[self addChildViewController:SecondChildVC];
[SecondChildVC didMoveToParentViewController:self];
}
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
if(UIInterfaceOrientationIsPortrait(fromInterfaceOrientation)) {[self transitionFromViewController:FirstChildVC toViewController:SecondChildVC duration:0.5 options:UIViewAnimationOptionTransitionCrossDissolve animations:nil completion:nil];
[FirstChildVC didMoveToParentViewController:self];}
if(UIInterfaceOrientationIsLandscape(fromInterfaceOrientation)) {[self transitionFromViewController:SecondChildVC toViewController:FirstChildVC duration:0.5 options:UIViewAnimationOptionTransitionCrossDissolve animations:nil completion:nil];
[SecondChildVC didMoveToParentViewController:self];}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
Next we'll create the first child view controller (called here FirstChildViewController).
FirstChildViewController.m
#import "FirstChildViewController.h"
@implementation FirstChildViewController
-(void)willMoveToParentViewController:(UIViewController *)parent
{
NSLog(@"FirstViewController moving to or from parent view controller");
self.view.backgroundColor=[UIColor blueColor];
}
-(void)didMoveToParentViewController:(UIViewController *)parent
{
NSLog(@"FirstViewController did move to parent view controller");
self.view.frame = CGRectMake(0,0,768, 1024);
}
@end
And finally the second child view controller (called here SecondChildViewController).
SecondChildViewController.m
#import "SecondChildViewController.h"
@implementation SecondChildViewController
-(void)willMoveToParentViewController:(UIViewController *)parent
{
NSLog(@"SecondViewController moving to or from parent view controller");
self.view.backgroundColor=[UIColor yellowColor];
}
-(void)didMoveToParentViewController:(UIViewController *)parent
{
NSLog(@"SecondViewController did move to parent view controller");
self.view.frame = CGRectMake(0,0, 1024,768);
}
@end
@implementation SecondChildViewController
-(void)willMoveToParentViewController:(UIViewController *)parent
{
NSLog(@"SecondViewController moving to or from parent view controller");
self.view.backgroundColor=[UIColor yellowColor];
}
-(void)didMoveToParentViewController:(UIViewController *)parent
{
NSLog(@"SecondViewController did move to parent view controller");
self.view.frame = CGRectMake(0,0, 1024,768);
}
@end
As long as you know how to create a project file and subsequent UIViewController subclass files, you should be able to copy and paste this code then build and run it on a device. Next turn the device and you should see the screen change colour.
Stupid tut! You are not descriptive enough man!!! Come on..
ReplyDeleteStephanus, if you let me know in which areas you are having problems then perhaps I can help.
ReplyDeleteMan, I am having some problem, I use your Tutorial but I am in doubt in some things. My e-mail guilhermerosa93@gmail.com
ReplyDeleteI've updated the post to provide full code at the end. Please let me know if this clears things up or if you'd still like me to email.
DeleteI am new to xcode and please help me in this doubt Where i should add it FirstChildVC = [[FirstChildViewController alloc] init];
ReplyDeletewhether in the method below
-(void)willMoveToParentViewController:(UIViewController *)parent
please explain about that briefly sir. Thanks in advance!!!
The simplest place to use FirstChildVC = [[FirstChildViewController alloc] init]; is in the viewDidLoad method of the initial view controller, although this is not the only place it can go.
DeleteThe willMoveToParentViewController method goes inside the FirstChildViewController.m file and will be called when an instance is added to the initial view as you will see from the NSLog messages.
Hi,
DeleteI am on new on Swift Ios developer. Could you please send me the source code of this sample. Thanks Md Maidul Islam