# UISplitViewController

By [Natasha Murashev](https://nshipster.com/authors/natasha-murashev).
Published 2014-11-03; updated 2018-09-26.
Canonical URL: <https://nshipster.com/uisplitviewcontroller>

In the beginning, there was the iPhone. And it was good.

Some years later, the iPad was introduced. And with some adaptations, an iOS app could be made Universal to accommodate both the iPhone and iPad in a single bundle.

For a while, the split between the two was the _split_ itself — namely `UISplitViewController`. Given a classic master-detail view controller paradigm, an iPhone would display each on separate screens, whereas an iPad would display both side-by-side.

But over time, the iPhone grew in size and the distinction between phone and tablet began to blur. Starting with the iPhone 6+, apps running in landscape mode on the phone had enough screen real estate to act like they were on a tablet.

Although user interface idioms have made way for the broader concept of size classes, `UISplitViewController` remains a workhorse API for writing Universal apps. This week, let’s take a closer look at how we can use it to adapt our UI to a variety of screen sizes.

---

Let’s start with an example of `UISplitViewController` working its magic on a large iPhone:

[![Screen recording of a split view app on a large iPhone in landscape, with a list of colors beside the selected color](https://nshipster.com/assets/split-view-demo-0c76fbba058596c1.jpg)](https://nshipster.com/assets/split-view-demo-19435acf6dcda2ff.mov)

However, the view doesn’t split when the iPhone is in _Zoomed_ Display mode.

[![Screen recording of the same app in Zoomed Display mode, where the list of colors and the selected color take turns filling the screen](https://nshipster.com/assets/split-view-zoomed-demo-426bcb394f93e6cf.jpg)](https://nshipster.com/assets/split-view-zoomed-demo-6907f1b2ec80e442.mov)

> You can change between Standard and Zoomed Display Mode in Settings by going to Display & Brightness → View (under Display Zoom) and selecting Standard or Zoomed.

This is one instance of how split views automatically determine when to show split views.

## Split View Controller, from Start to Finish

The best way to understand how `UISplitViewController` works is to show a complete example. The source code for the example project in this post [can be found here](https://github.com/NSHipster/UISplitViewControllerDemo).

### The Storyboard Layout

Here’s an overview of what a storyboard layout looks like with a split view controller:

![UISplitViewController Storyboard Layout](https://nshipster.com/assets/uisplitviewcontroller-storyboard-layout-93fa480ecf890a14.png)

In order to _master_ this concept, let’s dive into more _detail_.

### Master / Detail

The first step to using a `UISplitViewController` is dragging it onto the storyboard. The next step is to specify which view controller is the master and which one is the detail.

![UISplitViewController Master-Detail Storyboard](https://nshipster.com/assets/uisplitviewcontroller-master-detail-storyboard-d381f0a7cfc86657.png)

You can do this by selecting the appropriate Relationship Segue:

![UISplitViewController Relationship Segue](https://nshipster.com/assets/uisplitviewcontroller-relationship-segue-3a1abe383127e9f9.png)

The master view controller is typically the navigation controller that contains the list view (a `UITableView` in most cases); the detail view controller is the navigation controller that contains the view that shows up when the user taps on the list item.

### Show Detail

There’s one last part to making the split view controller work: specifying the “Show Detail” segue.

![UISplitViewController Show Detail Segue](https://nshipster.com/assets/uisplitviewcontroller-show-detail-segue-28e5a919aacd062c.png)

In the example below, when the user taps on a cell in the `ColorsViewController`, they’re shown a navigation controller with the `ColorViewController` at its root.

### Double Navigation Controllers‽

At this point, you might be wondering: _Why do the master and detail view controllers have to be navigation controllers — especially when there’s already a “Show Detail” segue?_

Well, let’s see what happens when the detail view controller doesn’t have a navigation controller at its root:

![UISplitViewController No Detail Navigation Controller](https://nshipster.com/assets/uisplitviewcontroller-no-detail-navigation-controller-c4e5e6a4d0a7bca0.png)

By all accounts, the app would still work just fine. On a large iPhone, the only difference is the lack of a navigation bar when the phone is in landscape mode:

![UISplitViewController No Navigation Bar](https://nshipster.com/assets/uisplitviewcontroller-no-navigation-bar-d826334227cfd8d4.png)

It’s not a big deal unless you want your navigation bar to show a title. But this is a deal-breaker on an iPad:

[![Screen recording of the app on an iPad, which launches to an empty detail view with no navigation bar or button to show the list of colors](https://nshipster.com/assets/ipad-split-view-no-navigation-bar-2d065e7a0ff104df.jpg)](https://nshipster.com/assets/ipad-split-view-no-navigation-bar-0b61e0423a0d3713.mov)

Notice that when the iPad app first launches, there’s no indication that there’s a split view controller at all! To trigger the master view controller, the user has to magically know to swipe left-to-right.

### Adding a Display Mode Button

To resolve this issue, we’re looking for some way to indicate that there’s more to the app than what’s currently on-screen. Luckily, `UISplitViewController` has a `displayModeButtonItem` navigation item, which can be added to the navigation bar to give us the visual indicator we seek:

```swift
override func viewDidLoad() {
    super.viewDidLoad()

    <#…#>

    navigationItem.leftBarButtonItem =
        splitViewController?.displayModeButtonItem
    navigationItem.leftItemsSupplementBackButton = true
}
```

```objc
- (void)viewDidLoad {
    [super viewDidLoad];

    <#…#>

    self.navigationItem.leftBarButtonItem =
        self.splitViewController.displayModeButtonItem;
    self.navigationItem.leftItemsSupplementBackButton = YES;
}
```

_Build and Run_ on the iPad again, and now you get a nice indication of how to access the rest of the app:

[![Screen recording of the app on an iPad, with a navigation bar button that shows the list of colors](https://nshipster.com/assets/ipad-navigation-bar-with-button-9518cd227a38921d.jpg)](https://nshipster.com/assets/ipad-navigation-bar-with-button-9819a68ec622df11.mov)

The `displayModeButtonItem` property lends some nice usability to apps running on large iPhones in landscape mode, too:

[![Screen recording of the app on a large iPhone in landscape, where the display mode button expands the selected color to fill the screen](https://nshipster.com/assets/iphone-displayModeButtonItem-eb3e8ee84759bffb.jpg)](https://nshipster.com/assets/iphone-displayModeButtonItem-92a24b17fac498f5.mov)

By using `displayModeButtonItem`, you let iOS figure out what’s appropriate for the current screen size and orientation. Instead of sweating the small (and big) stuff yourself, you can sit back and relax. 🍹

## Collapse Detail View Controller

There’s one more optimization we can do for the iPhone. When the user first launches the app, let’s make the master view controller display fully until the user selects a list item. We can do that using [`UISplitViewControllerDelegate`](https://developer.apple.com/documentation/uikit/uisplitviewcontrollerdelegate):

```swift
class ColorsViewController: UITableViewController {
    var collapseDetailViewController: Bool = true

    <#…#>

    // MARK: - UITableViewDelegate

    override func tableView(_ tableView: UITableView,
                            didSelectRowAt indexPath: IndexPath)
    {
        self.collapseDetailViewController = false
    }
}

class SplitViewDelegate: NSObject, UISplitViewControllerDelegate {
    <#…#>

    func splitViewController(_ splitViewController: UISplitViewController,
                             collapseSecondary secondaryViewController: UIViewController,
                             onto primaryViewController: UIViewController) -> Bool
    {
        guard let navigationController = primaryViewController as? UINavigationController,
            let controller = navigationController.topViewController as? ColorsViewController
        else {
            return true
        }

        return controller.collapseDetailViewController
    }
}
```

```objc
// SelectColorTableViewController.h

@interface SelectColorTableViewController :
            UITableViewController <UISplitViewControllerDelegate>
@end

// SelectColorTableViewController.m

@interface SelectColorTableViewController ()
@property (nonatomic) BOOL shouldCollapseDetailViewController;
@end

@implementation SelectColorTableViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    self.shouldCollapseDetailViewController = YES;
    self.splitViewController.delegate = self;
}

#pragma mark - UITableViewDelegate

- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    self.shouldCollapseDetailViewController = NO;
}

#pragma mark - UISplitViewControllerDelegate

- (BOOL)splitViewController:(UISplitViewController *)splitViewController
collapseSecondaryViewController:(UIViewController *)secondaryViewController
      ontoPrimaryViewController:(UIViewController *)primaryViewController {
    return self.shouldCollapseDetailViewController;
}

@end
```

Now when the app launches on an iPhone in portrait orientation, `ColorsViewController` is in full view. Once the user selects a color (or the app goes into the background), `ColorsViewController` is collapsed again, and `ColorViewController` is displayed:

[![Screen recording of the app in the iOS Simulator as an iPhone 6 Plus rotates between portrait and landscape orientations](https://nshipster.com/assets/iphone-primary-view-controller-rotation-e5d0811d07383cd9.jpg)](https://nshipster.com/assets/iphone-primary-view-controller-rotation-18aae2f3734fac85.mov)

---

iOS is always adapting to new capabilities from new hardware. When retina screens were introduced, developers could no longer assume that 1pt = 1px. When larger iPhones were introduced, developers could no longer assume a single screen size.

Today, we’re responsible for accommodating several generations of iPhones and iPads, as well as external displays and various accessibility features. This would be a nightmare if it weren’t for the powerful and thoughtful APIs provided in iOS.

`UISplitViewController` may not be the newest API on the block when it comes to adapting to various interface conditions, but it remains a useful tool for quickly creating robust apps.
