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)

3) in the implementation (.m) files of the first and second child view controllers, which I've called FirstChildViewController and SecondChildViewController, you'll need to add two new methods:


-(void)willMoveToParentViewController:(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);
}

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);
}


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];
}


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];}
   
}

(the transition doesn't actually add or remove the child view controllers - it only replaces their view - but we call the didMoveToParentViewController: method again for convenience to create the frame again for our view that has just been removed because it will come back again on the next rotation)

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).

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


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

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.


Endorse on Coderwall

Comments

  1. Stupid tut! You are not descriptive enough man!!! Come on..

    ReplyDelete
  2. Stephanus, if you let me know in which areas you are having problems then perhaps I can help.

    ReplyDelete
  3. Man, I am having some problem, I use your Tutorial but I am in doubt in some things. My e-mail guilhermerosa93@gmail.com

    ReplyDelete
    Replies
    1. I'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.

      Delete
  4. I am new to xcode and please help me in this doubt Where i should add it FirstChildVC = [[FirstChildViewController alloc] init];
    whether in the method below
    -(void)willMoveToParentViewController:(UIViewController *)parent
    please explain about that briefly sir. Thanks in advance!!!

    ReplyDelete
    Replies
    1. 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.

      The 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.

      Delete
    2. Hi,
      I am on new on Swift Ios developer. Could you please send me the source code of this sample. Thanks Md Maidul Islam

      Delete

Post a Comment