Select Page

The split view is something very cool within the new iPhone OS 3.2. It allows us to visualize a master-detail view in a very simple manner. Combined with iPads’ big display of 1024×748 pixels it will be possible to create even better, more user-friendly and valuable applications.

Basically, the split view consists of two separate views. The master view will be shown in a 320 pixel width part on your screen if your iPad is at landscape orientation, otherwise the master view will be accessible as a popover view. The details view should show your main content and will be at full size if your iPad is at portrait orientation. Mainly the user will be focused at your details view and this fact you should keep in mind.

Creating a split view pragmatically within your application is a easy task. The following code will show this:

//create the master view
MasterViewController *masterView = [[MasterViewController alloc]
                initWithNibName:@"Master"
                bundle:[NSBundle mainBundle]];

//create the details view
DetailsViewController *detailsView = [[DetailsViewController alloc]
                initWithNibName:@"Details"
                bundle:[NSBundle mainBundle]];

//create the split view
UISplitViewController *splitController =
                [[UISplitViewController alloc] init];

//set the view controllers array
splitController.viewControllers = [NSArray
                arrayWithObjects:masterView, detailsView, nil];

//show split view as the main view
[window addSubview:splitController.view];
[window makeKeyAndVisible];

//release view
[masterView release];
[detailsView release];

Next we want to access the master view via a popover view, when the iPad is in portrait mode. The shouldAutorotateToInterfaceOrientation:  method of your master and detail controller must support all orientations, otherwise it wont be possible to rotate a split view. After that implement the UISplitViewControllerDelegate  protocol in any class and set the delegate of your split view controller. The methods within this protocol will be called whenever the master view will be hidden or shown again.

In my example I created another class which gets a reference to the details view controller and holds the toolbar object we will use to present the popover button. The following code is pretty simple and contains the three methods of the UISplitViewControllerDelegate  protocol. The first method is called whenever the master view will be hidden. So in this case we will add a toolbar with the given popover button to our detail view. You are free to label the button as you like. The second method is called whenever the master view will be shown again. Now we simply hide the toolbar. So, that’s pretty all. The displaying logic of your master view within a popover view is done automatically, but you can still modify it within the last method (which is empty in my case).

//the master view controller will be hidden
- (void)splitViewController:(UISplitViewController*)svc
    willHideViewController:(UIViewController *)aViewController
    withBarButtonItem:(UIBarButtonItem*)barButtonItem
    forPopoverController:(UIPopoverController*)pc {

  if(toolBar == nil) {
    //set title of master button
    barButtonItem.title = @"Show Master";

    //create a toolbar
    toolBar = [[UIToolbar alloc]
                    initWithFrame:CGRectMake(0, 0, 1024, 44)];
    [toolBar setItems:[NSArray arrayWithObject:barButtonItem]
                    animated:YES];
  }

  //add the toolbar to the details view
  [detailController.view addSubview:toolBar];
}

//the master view will be shown again
- (void)splitViewController:(UISplitViewController*)svc
    willShowViewController:(UIViewController *)aViewController
    invalidatingBarButtonItem:(UIBarButtonItem *)button {

  //remove the toolbar
  [toolBar removeFromSuperview];
}

// the master view controller will be displayed in a popover
- (void)splitViewController:(UISplitViewController*)svc
    popoverController:(UIPopoverController*)pc
    willPresentViewController:(UIViewController *)aViewController {

  //empty for now

}

Well, you need to do something more than this if you want to create really useful split view applications. Often it will be wise to use a table view as your master. Some things I found out while playing around with the split view are:

  • You are not able to present a split view as a modal view
  • If the master or detail view doesn’t allow all interface orientations, the split view will not work properly. So if you don’t see the master view check your shouldAutorotateToInterfaceOrientation  method within your view controller.

Update

Some people asked me if it is possible to keep the master view visible even in portrait mode. I tried around and found following working solution:

Create a subclass of UISplitViewController  and just overwrite the method willAnimateRotationToInterfaceOrientation: duration: . This method will be called whenever the orientation of a view is going to be changed. Everything you have to do is to check if the interface will change to a portrait method and if that is true, adjust the visible frames of your master and detail views. Find below the code I used to get this working:

/**
 * Sent to the view controller just before
 * the user interface begins rotating.
 */
- (void)willAnimateRotationToInterfaceOrientation:
      (UIInterfaceOrientation)interfaceOrientation
      duration:(NSTimeInterval)duration {

  //get master and detail view controller
  UIViewController* master = [self.viewControllers objectAtIndex:0];
  UIViewController* detail = [self.viewControllers objectAtIndex:1];

  //only handle the interface orientation
  //of portrait mode
  if(interfaceOrientation == UIInterfaceOrientationPortrait ||
        interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown) {
        //adjust master view
        CGRect f = master.view.frame;
        f.size.width = 320;
        f.size.height = 1024;
        f.origin.x = 0;
        f.origin.y = 0;

        [master.view setFrame:f];

        //adjust detail view
        f = detail.view.frame;
        f.size.width = 830;
        f.size.height = 1024;
        f.origin.x = 320;
        f.origin.y = 0;

        [detail.view setFrame:f];
  }
  else {
        //call super method
        [super willAnimateRotationToInterfaceOrientation:interfaceOrientation
                    duration:duration];
  }
}

Now, just use your own UISplitViewController  subclass within your code and the master view should stay visible even in portrait mode.