Toggling Full-Screen Split View Controllers in iOS 8

Split View Controller on iPad with full screen toggle button

I had some trouble understanding exactly how to get a split view controller to have a toggling master view controller. The problem was that I assumed I needed to manage my own UIBarButtonItem that calls a method on the split view controller.

There are a few pieces I had to put together to get the functionality I wanted.

First, I had to set my split view controller’s preferredDisplayMode to UISplitViewControllerDisplayModeAllVisible. This displays the master on the left, detail on the right.

Next I needed a button toggle the master view controller.

After re-watching WWDC session 204 (text version here), I realised that the UISplitViewController actually provides you with the button through its displayModeButtonItem.

So basically if you put the button in a toolbar or navigation bar, its state, target, and action are going to be managed for you.

I set the toolbar button when the detail view controller gets set. In my storyboard-based app it looks like this:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if ([[segue identifier] isEqualToString:@"showDetail"]) {
        DetailViewController *controller = (DetailViewController *)[[segue destinationViewController] topViewController];

        // Set a few properties for the detail view here...
        // ...

        // And set the button item.
        controller.navigationItem.leftBarButtonItem = self.splitViewController.displayModeButtonItem;
    }
}

The last piece of the puzzle was getting the toggle action set up properly. Since the appearance of the button that the split view controller provides depends on what will happen when you press it, you need to specify what will happen. You do this in the UISplitViewControllerDelegate’s targetDisplayModeForActionInSplitViewController:. For me, that looks like this:

- (UISplitViewControllerDisplayMode)targetDisplayModeForActionInSplitViewController:(UISplitViewController *)svc {
    if (svc.displayMode == UISplitViewControllerDisplayModePrimaryOverlay || svc.displayMode == UISplitViewControllerDisplayModePrimaryHidden) {
        return UISplitViewControllerDisplayModeAllVisible;
    }
        return UISplitViewControllerDisplayModePrimaryHidden;
}

With very little code and no third-party dependencies, I’ve got a universal split view controller that behaves as you’d expect on all iOS devices, with an option to hide the master controller.