An iPad iOS 7 Split View and Popover Example

From Techotopia
Revision as of 18:03, 11 May 2016 by Neil (Talk | contribs) (Text replacement - "<htmlet>ezoicbottom</htmlet>" to "")

Jump to: navigation, search
PreviousTable of ContentsNext
Using an Xcode 5 Storyboard to Create a Static Table ViewImplementing a Page based iOS 7 Application using UIPageViewController


Learn SwiftUI and take your iOS Development to the Next Level
SwiftUI Essentials – iOS 16 Edition book is now available in Print ($39.99) and eBook ($29.99) editions. Learn more...

Buy Print Preview Book


Whilst it is possible to use the UITableView class as both an information display and application navigation tool on iPhone applications, it is extremely inefficient in terms of the use of screen space when used on an iPad. In recognition of this fact, Apple introduced the Split View and Popover concepts for use when developing iOS applications specifically for the iPad.

The purpose of this chapter is to provide an overview of Split Views and Popovers followed by a tutorial that implements these concepts in a simple example iPad application.


Contents


An Overview of Split View and Popovers

When an iPad is in landscape mode, the UISplitViewController class divides the screen into two side-by-side panels which implement a master-detail model. Within this model, the left hand panel is the master panel and presents a list of items to the user. The right hand panel is the detail panel and displays information relating to the currently selected item in the master panel.

A prime example of this concept in action can be seen with the iPad Mail app which lists messages in the master panel and displays the content of the currently selected message in the detail panel.

When an iPad device is in portrait mode, however, the Split View Controller hides the master panel so that the detail panel is able to utilize the entire screen. In this instance, access to the master panel is provided using a Popover. A popover is a window that appears over the top of the current view and, in a split view situation, is typically accessed via a button placed in the toolbar of the detail view. When the device is rotated back to landscape orientation, the master and detail panels appear side by side once again and the popover access button is removed from view.

The UISplitterViewController is essentially a container to which two child view controllers are added to act as the master (also referred to as the root view controller) and detail views. The detail view controller is usually designated as a delegate to the splitter view controller in order to receive notifications relating to orientation changes, primarily so that the popover button may be hidden and displayed accordingly.

In the remainder of this chapter we will work through a tutorial that involves the creation of a simple iPad application that demonstrates the use of a split view and popover.

About the Example iPad Split View and Popover Project

The goal of this tutorial is to create an iPad application containing a split view user interface. The master panel will contain a table view listing a number of web site addresses. When a web site URL is selected from the list, the detail panel will load the corresponding web site and display it using a UIWebView component. When rotated into portrait mode, a button will appear in the navigation bar of the detail view which, when selected, will display the master list in a popover.


Creating the Project

Begin by launching Xcode and creating a new iPad iOS application using the Master-Detail Application template. Enter SplitView as the product name and class prefix, select iPad from the Devices menu and verify that the Use Core Data option is switched off.

By using this template we save a lot of extra coding effort in the implementation of the split view and popover behavior. Much of the code generated for us is standard boilerplate code that does not change from one split view implementation to another. In fact, much of this template can be copied even if you plan to hand code split view behavior in future applications. That said, there are some unusual aspects to the template which will need to be modified during the course of this tutorial.

Reviewing the Project

The Split View template has created a number of project files for us. The most significant of these are the files relating to the Master View Controller and Detail View Controller classes. These classes correspond to the master and detail views and are named SplitViewMasterViewController and SplitViewDetailViewController respectively. Xcode has also created a custom didFinishLaunchingWithOptions method located within the SplitViewAppDelegate class. Whilst the custom didFinishLaunchingWithOptions method fits perfectly with our requirements, the template actually creates a simple application in which the date and time may be added to the master view and then displayed in the detail view when selected. Since this is not quite the behavior we need for our example it will be necessary to delete some of this template code as our project progresses.

Finally, a Main.storyboard file has been created configured with the following elements:

  • A UISplitViewController
  • A View Controller named SplitViewDetailViewController for the detail pane
  • A Table View Controller name SplitViewMasterViewController for the master pane
  • Two navigation controllers

This represents the standard storyboard configuration for a typical split view implementation. The only changes to this storyboard that will be necessary for this example will be to change the user interface of the detail view pane and to modify the title of the master pane. The rest of the storyboard will remain unchanged. To change the title of the master pane, locate it within the storyboard canvas, double click on the title text which currently reads “Master” and enter “Favorite Web Sites” as the new title as outlined in Figure 26-1:


Ios 7 splitview change master title.png

Figure 26-1


Configuring Master View Items

The master view controller created for us by Xcode is actually a subclass of UITableView. The next step, therefore, is to configure the table view to display the list of web sites. For this purpose we will need to configure two array objects to store the web site names and corresponding URL addresses. Select the SplitViewMasterViewController.h file and modify it as follows to declare these two arrays:

#import <UIKit/UIKit.h>

@class SplitViewDetailViewController;

@interface SplitViewMasterViewController : UITableViewController

@property (nonatomic, retain) NSArray *siteNames;
@property (nonatomic, retain) NSArray *siteAddresses;

@property (strong, nonatomic) SplitViewDetailViewController *detailViewController;

@end

Having declared the arrays, modify the SplitViewMasterViewController.m file to initialize the arrays in the viewDidLoad method. Note that Xcode has already added some code to the viewDidLoad method for the template example so be sure to remove this before adding the new code below:

- (void)viewDidLoad
{
    [super viewDidLoad];
    _siteNames = [[NSArray alloc] initWithObjects:@"Yahoo", @"Google",
        @"Apple", @"eBookFrenzy", nil];

    _siteAddresses = [[NSArray alloc]
         initWithObjects:@"http://www.yahoo.com",
           @"http:/www.google.com", @"http://www.apple.com",
           @"http://www.ebookfrenzy.com", nil];

    self.detailViewController = (SplitViewDetailViewController *) 
         [[self.splitViewController.viewControllers lastObject] 
             topViewController];
}

Learn SwiftUI and take your iOS Development to the Next Level
SwiftUI Essentials – iOS 16 Edition book is now available in Print ($39.99) and eBook ($29.99) editions. Learn more...

Buy Print Preview Book

There are a number of methods that must be implemented in order for the items to appear within the table view object. Fortunately, Xcode has already placed template methods for us to use in the SplitViewMasterViewController.m file. First, modify the numberOfRowsInSection method to notify the table view of the number of items to be displayed (in this case, a value equal to the number of items in our siteNames array). Since there is only one section in the table also modify the numberOfSectionsInTableView method accordingly. Note that Xcode has, once again, added some code for the template example so be sure to remove this code where necessary:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView 
numberOfRowsInSection:(NSInteger)section
{
    return _siteNames.count;
}

Next, modify the cellForRowAtIndexPath method to return the item to be displayed, using the row number argument as an index into the siteNames array:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView 
         dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] 
               initWithStyle:UITableViewCellStyleDefault 
               reuseIdentifier:CellIdentifier];
    }

    //NSDate *object = _objects[indexPath.row];
    //cell.textLabel.text = [object description];

    cell.textLabel.text = _siteNames[indexPath.row];
    return cell;
}

Click on the Run button located in the Xcode toolbar to test the current state of the application. Once the application loads into the iOS iPad simulator, rotate the device into landscape mode (Hardware -> Rotate Left):


Ios 7 splitview master table.png

Figure 26-2


At this point the items in the master panel actually load the detail view onto the master panel when selected and the detail panel still displays the place holder label provided by Xcode when the project was first created. The next step is to change this behavior and add the web view to the detail view controller.

Configuring the Detail View Controller

When a user selects a web site item from the master panel, the detail panel will load the selected web site into a web view object.

Begin by selecting the Main.storyboard file, locate the SplitViewControllerViewController scene, highlight the placeholder label that reads “Detail view content goes here” and press the Delete key. Drag and drop a UIWebView object from the object library (View -> Utilities -> Show Object Library) onto the view and resize it so that it fills the available space.

Select the web view object, display the Assistant Editor panel and verify that the editor is displaying the contents of the SplitDetailViewController.h file. Ctrl-click on the web view again and drag to a position just below the @interface line in the Assistant Editor. Release the line and in the resulting connection dialog establish an outlet connection named webView.

Connecting Master Selections to the Detail View

All that now remains is to configure the detail panel to update based on selections made in the master panel. When a user makes an item selection from the table view the didSelectRowAtIndexPath method in the master view controller is triggered. This template method needs to be modified to load the corresponding web site into the web view. Select the SplitViewMasterViewController.m file and locate the method. Once again, Xcode has added code to the template example so remove the current code and modify the method as follows:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSString *urlString = [_siteAddresses
                 objectAtIndex:indexPath.row];
    NSURL *url = [NSURL URLWithString:urlString];

    NSURLRequest *request = [NSURLRequest requestWithURL:url];

    self.detailViewController.webView.scalesPageToFit = YES;

    [self.detailViewController.webView loadRequest:request];
}

The method begins by identifying the URL of the selected web site by using the selected row as an index into the siteAddresses array which is then used to construct NSURL and NSURLRequest objects.

Next a reference to the detail view controller is obtained by accessing the detailViewController property of the master view controller.

Note that in order to make the web page scale to fit the detail view area the scalePagesToFit property of the UIWebView object is set to YES. Finally, the web view object in the detail view controller is instructed to load the web URL.

Popover Implementation

In actual fact the popover code was already implemented for us by Xcode when we selected the option to create a Master-Detail application. That said, it is worth taking the time to look at this code, which consists of two delegate methods in the SplitViewDetailViewController.m file. The first method is called when the device rotates to portrait orientation and reads as follows:

- (void)splitViewController:(UISplitViewController *)splitController willHideViewController:(UIViewController *)viewController withBarButtonItem:(UIBarButtonItem *)barButtonItem forPopoverController:(UIPopoverController *)popoverController
{
    barButtonItem.title = NSLocalizedString(@"Master", @"Master");
    [self.navigationItem 
         setLeftBarButtonItem:barButtonItem animated:YES];
    self.masterPopoverController = popoverController;
}

This method configures the toolbar to display a button with the title “Master” and sets up the popover controller assignment. Before proceeding, modify the title line of code to display the “Favorite Web Sites” title:

self.barButtonItem.title = NSLocalizedString(@"Favorite Web Sites", @"Favorite Web Sites");

The second method simply removes the button from the toolbar and de-assigns the popoverController reference:

- (void)splitViewController:(UISplitViewController *)splitController 
willShowViewController:(UIViewController *)viewController 
invalidatingBarButtonItem:(UIBarButtonItem *)barButtonItem
{
    // Called when the view is shown again in the split view, 
    // invalidating the button and popover controller.
    [self.navigationItem setLeftBarButtonItem:nil animated:YES];
    self.masterPopoverController = nil;
}

Testing the Application

All that remains is to test the application so click on the Run button and wait for the application to load into the iOS iPad Simulator. In portrait mode only the detail panel should be visible. Tap the “Favorite Web Sites” button to display the popover and select a website from the list so that it loads into the detail view:


An iOS 7 Split View example in portrait orientation

Figure 26-3


Select the Hardware -> Rotate Left menu option to switch the device into landscape mode and note that both the master and detail panels are now visible:


An iOS 7 Split View example in landscape orientation

Figure 26-4


Summary

Split views provide iPad applications with a master-detail interface paradigm designed to make better use of the larger screen space of the device. Where ever possible, this approach should be taken in favor of the table view based navigation common in iPhone based applications. In this chapter we have explored split views and popovers in general and worked through the implementation of an example application.


Learn SwiftUI and take your iOS Development to the Next Level
SwiftUI Essentials – iOS 16 Edition book is now available in Print ($39.99) and eBook ($29.99) editions. Learn more...

Buy Print Preview Book



PreviousTable of ContentsNext
Using an Xcode 5 Storyboard to Create a Static Table ViewImplementing a Page based iOS 7 Application using UIPageViewController