An often ignored but rather powerful View Controller is the UISplitViewController
. You can make one from a template and the storyboard, but I often skip both and do it programmatically, which is especially good when I’m prototyping in a playground. Let’s give it a try using the exercise files I’ve been using for the past few tips. There we added a color table. Split view controllers have a master, which I’ll make the color table, and the detail, which will tell us the color name, and show the color.
Head over to the AppDelegate in this project. Split View controllers should be your root view, and you have two view controllers be the roots for the detail and master view. I usually embed the root view controllers in navigation controllers, so I can add view controllers off that. I did that for the master already. I only need the detail, which I can do like this:
let colorDetailViewController = ColorDetailViewController() let detailNavigationViewController = UINavigationController(rootViewController: colorDetailViewController)
I’ll instantiate a split view controller.
let splitViewController = UISplitViewController()
You assign the master and detail to the viewControllers
property, which is an array of two elements. The first element of the array is the master and the second the detail.
splitVC.viewControllers = [navigationVC,colorDetailVC]
I like doing one more thing to control the width of the master view. I’ll set the property preferredPrimaryColumnWIdthFraction
to a proportion. I’ll set this one to 1/3.
splitVC.preferredPrimaryColumnWidthFraction = 1/3
Finally, assign the splitViewController
to the window
‘s rootViewController
.
window?.rootViewController = splitViewController
Build and run this on an iPhone XR simulator. You’ll just get a single view of the detail. On a compressed width, such as you get in portrait, you get only one of the two views.

On a regular width you’ll get both. Rotate the simulator with a command-left arrow. In Portrait, you see the master and detail.

If you tap a color, it still doesn’t do anything in the detail. I’d like to show the color on the detail when selected from the mater. These are two view controllers without any way to communicate with each other. I’ll use delegation here.
Stop the app. If you go to HueColorTableViewController
, you’ll see I made a protocol and delegate. I’ll add the delegate’s method to the code here in did select
delegate.didSelectColor(color: colors[row])
In the ColorDetailViewController
, I’ll adopt the delegate
UIViewController,HueColorTableViewControllerDelegate {
I added a callback to change the background color and display the name.
Go back to AppDelegate
and add a line to direct the delegate correctly.
colorTVC.delegate = colorDetailVC
Run that, and you get the same split view controller, but select a color and it appears.

That’s the basics of adding a split view controller to a project programmatically.
The Whole Code
Below you’ll find the code for this project. You can also download the code from GitHub here.
AppDelegate.swift
// // AppDelegate.swift // ColorPicker // // // An exercise file for iOS Development Tips Weekly // by Steven Lipton (C)2018, All rights reserved // For videos go to http://bit.ly/TipsLinkedInLearning // For code go to http://bit.ly/AppPieGithub // import UIKit @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { window = UIWindow(frame: UIScreen.main.bounds) // Instantiate root view controllers let hueColorTableViewController = HueColorTableViewController() let colorDetailViewController = ColorDetailViewController() hueColorTableViewController.delegate = colorDetailViewController // Embed in navigation controllers let masterNavigationViewController = UINavigationController(rootViewController: hueColorTableViewController) let detailNavigationController = UINavigationController(rootViewController: colorDetailViewController) // Embed in Split View controller let splitViewController = UISplitViewController() splitViewController.viewControllers = [masterNavigationViewController,detailNavigationController] splitViewController.preferredPrimaryColumnWidthFraction = 1/3 // Root view controller of window window?.rootViewController = splitViewController window?.makeKeyAndVisible() return true } }
HueColorTable.swift
// // HueColorTableViewController.swift // ColorPicker // // // An exercise file for iOS Development Tips Weekly // by Steven Lipton (C)2018, All rights reserved // For videos go to http://bit.ly/TipsLinkedInLearning // For code go to http://bit.ly/AppPieGithub // import UIKit protocol HueColorTableViewControllerDelegate{ func didSelectColor(color:ColorEntry) } class HueColorTableViewController:UITableViewController{ var delegate:HueColorTableViewControllerDelegate! = nil var colors:[ColorEntry] = ColorModel().hues(count: 12) override func numberOfSections(in tableView: UITableView) -> Int { return 1 } override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return colors.count } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { var cell = tableView.dequeueReusableCell(withIdentifier: "cell") if cell == nil { cell = UITableViewCell(style: .default, reuseIdentifier: "cell") } let row = indexPath.row cell?.contentView.backgroundColor = colors[row].color cell?.textLabel?.text = colors[row].name cell?.textLabel?.numberOfLines = 0 return cell! } override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let row = indexPath.row title = colors[row].name delegate.didSelectColor(color: colors[row]) } override func loadView() { super.loadView() } }
ColorDetailViewController.swift
// // ColorDetailViewController.swift // ColorPicker // // An exercise file for iOS Development Tips Weekly // by Steven Lipton (C)2018, All rights reserved // For videos go to http://bit.ly/TipsLinkedInLearning // For code go to http://bit.ly/AppPieGithub // import UIKit class ColorDetailViewController: UIViewController, HueColorTableViewControllerDelegate { let colorLabel = UILabel() override func viewDidLoad() { super.viewDidLoad() addLayout() // Do any additional setup after loading the view. } //MARK:- Delegates func didSelectColor(color: ColorEntry) { view.backgroundColor = color.color colorLabel.text = color.name } //MARK:- Layout // All layout methods go here. func addLayout(){ colorLabel.text = "Color Detail" let font = UIFont(name: "AmericanTypewriter", size: 30)! colorLabel.font = font colorLabel.backgroundColor = .lightGray colorLabel.textAlignment = .center colorLabel.numberOfLines = 0 view.addSubview(colorLabel) colorLabel.translatesAutoresizingMaskIntoConstraints = false var constraints = [NSLayoutConstraint]() constraints += [NSLayoutConstraint(item: colorLabel, attribute: .leading, relatedBy: .equal, toItem: view.safeAreaLayoutGuide, attribute: .leading, multiplier: 1.0, constant: 0)] constraints += [NSLayoutConstraint(item: colorLabel, attribute: .trailing, relatedBy: .equal, toItem: view.safeAreaLayoutGuide, attribute: .trailing, multiplier: 1.0, constant: 0)] constraints += [NSLayoutConstraint(item: colorLabel, attribute: .top, relatedBy: .equal, toItem: view.safeAreaLayoutGuide, attribute: .top, multiplier: 1.0, constant: 0)] constraints += [NSLayoutConstraint(item: colorLabel, attribute: .height, relatedBy: .equal, toItem: view.safeAreaLayoutGuide, attribute: .height, multiplier: 1 / 9, constant: 0)] view.addConstraints(constraints) } }
ColorModel.swift
// // ColorModel.swift // ColorPicker // // // An exercise file for iOS Development Tips Weekly // by Steven Lipton (C)2018, All rights reserved // For videos go to http://bit.ly/TipsLinkedInLearning // For code go to http://bit.ly/AppPieGithub // import UIKit class ColorEntry{ var name:String = "" var color:UIColor var hue:CGFloat = 0.0 var brightness:CGFloat = 0.5 var saturation:CGFloat = 1.0 init(name:String,color:UIColor){ self.color = color self.name = name } } class ColorModel{ var colors = [ColorEntry]() init(){ colors = [] } func hues(count:Int)->[ColorEntry]{ colors = [] if count <= 0 {return colors} for hue in 0...count{ let hueValue = CGFloat(hue)/CGFloat(count) let color = UIColor(hue: hueValue, saturation: 1.0, brightness: 1.0, alpha: 1.0) let name = String(format:"H:%04.3f S:1.0 B:1.0 ",hueValue) let colorEntry = ColorEntry(name: name, color: color) colors += [colorEntry] } return colors } func lightnessScale(hue:UIColor,count:Int){ } }
Leave a Reply