Home > Articles > Programming > C/C++

  • Print
  • + Share This
This chapter is from the book

Recipe: Creating Universal Split View/Navigation Apps

Recipe 5-10 modifies Recipe 5-9's split view controller to provide a functionally equivalent application that runs properly on both iPhone and iPad platforms. Accomplishing this takes several steps that add to Recipe 5-9's code base. You do not have to remove functionality from the split view controller approach but you must provide alternatives in several places.

Recipe 5-10 depends on a macro that is used throughout which determines whether the code is being run on an iPad- or iPhone-style device:

#define IS_IPAD (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)

This macro returns YES when the device characteristics are iPad-like, rather than being iPhone-like (such as on the iPhone or iPod touch.) First introduced in iOS 3.2, idioms allow you to perform runtime checks in your code to provide interface choices that match the deployed platform.

In an iPhone deployment, the detail view controller remains code identical to Recipe 5-9, but to be displayed it must be pushed onto the navigation stack rather than shown side-by-side in a split view. The navigation controller is set up as the primary view for the application window rather than the split view. A simple check at application launch lets your code choose which approach to use:

- (UINavigationController *) navWithColorViewController
{
    ColorViewController *colorViewController =
        [ColorViewController controller];
    UINavigationController *nav = [[UINavigationController alloc]
        initWithRootViewController:colorViewController];
    return nav;
}

- (void)applicationDidFinishLaunching:(UIApplication *)application
{
    window = [[UIWindow alloc] initWithFrame:
        [[UIScreen mainScreen] bounds]];

    if (IS_IPAD)
        window.rootViewController = [self splitviewController];
    else
        window.rootViewController = [self navWithColorViewController];

    [window addSubview:mainController.view];
    [window makeKeyAndVisible];
}

The rest of the story lies in the two methods of Recipe 5-10, within the color-picking table view controller. Two key checks decide whether to show disclosure accessories and how to respond to table taps:

  • On the iPad, disclosure indicators should never be used at the last level of detail presentation. On the iPhone, they indicate that a new view will be pushed on selection. Checking for deployment platform lets your code choose whether or not to include these accessories in cells.
  • When you're working with the iPhone, there's no option for using split views, so your code must push a new detail view onto the navigation controller stack. Compare this to the iPad code, which only needs to reach out to an existing detail view and update its background color.

In real-world deployment, these two checks would likely expand in complexity beyond the details shown in this simple recipe. You'd want to add a check to your model to determine if you are, indeed, at the lowest level of the tree hierarchy before suppressing disclosure accessories. Similarly, you may need to update or replace presentations in your detail view controller.

Recipe 5-10. Adding Universal Support for Split View Alternatives

- (UITableViewCell *)tableView:(UITableView *)tableView
    cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell =
        [tableView dequeueReusableCellWithIdentifier:@"generic"];
    if (!cell) cell = [[UITableViewCell alloc]
        initWithStyle: UITableViewCellStyleDefault
        reuseIdentifier:@"generic"];

    cell.textLabel.text = @"Brightness";
    cell.textLabel.textColor =
        [UIColor colorWithWhite:(indexPath.row / 10.0f) alpha:1.0f];

    cell.accessoryType = IS_IPAD ?
        UITableViewCellAccessoryNone :
        UITableViewCellAccessoryDisclosureIndicator;

    return cell;
}

- (void)tableView:(UITableView *)tableView
    didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];

    if (IS_IPAD)
    {
        UIViewController *controller =
            (UIViewController *)self.splitViewController.delegate;
        controller.view.backgroundColor = cell.textLabel.textColor;
    }
    else
    {
        DetailViewController *controller = [
            DetailViewController controller];
        controller.view.backgroundColor = cell.textLabel.textColor;
        [self.navigationController
            pushViewController:controller animated:YES];
    }
}
  • + Share This
  • 🔖 Save To Your Account