[Updated for Xcode 7.2/Swift 2.1 2/5/16]
Note: Click here for the Swift 3.0/Xcode 8 version of this tutorial
In writing the Swift Swift View Controllers book, it came to my attention many people don’t understand the functionality of the navigation toolbar’s title and Back button. In an early part of writing, I planned to skip the topic as a minor detail so I could get the book done and published. However, the built-in features of the navigation toolbar make it a powerful and useful feature that can’t be missed.
Setting Up the Storyboard
Open up a new single view project named NavBarDemo using Swift as the language and Universal device. Go to the storyboard and click the view controller icon in the scene. In the drop down menu, select Editor>Embed in>Navigation controller. Drag two buttons, one labeled Pizza and the other labeled Pasta out to the scene. Make the Pizza button white text on a red background. Make the Pasta button white text on a blue background. Arrange them like this on the storyboard:
Select the Pizza button. Using auto layout, pin the button 0 points up, 0 left, 0 right, and 0 down like this:
Select the Pasta button and again pin the button button 0 up,0 left, 0 right, and 0 down. Now Control-drag from the Pizza button to the Pasta button. Select Equal Widths in the menu that appears.
On the resolver menu select Update Frame in the All Frames in View section. Your controller should look like this:
Drag two more view controllers on to the storyboard. Make the background of one blue and the background of the other red.
Control drag from the Pizza button to the red scene. Select a show segue. In the attributes inspector, set the segue identifier to pizza. Control-drag from the Pasta button to the blue scene. Select a show segue. In the properties inspector, set the segue identifier to pasta.
In this lesson we will do all the coding in ViewController
, so there is no need of code in the two new controllers.
Setting the Navigation Title Bar
There is a property on UIViewController
called navigationItem.
When used with navigation controllers, this controls the navigation bar at the top of the view. The navigationItem
property is an instance of UINavigationItem
, which contains four major properties: a title, a left bar button, a right bar button and a prompt. To set the title on the toolbar , you set the string for the title
property. For example add this to the ViewController
class
override func viewWillAppear(animated: Bool) { navigationItem.title = "One" }
Build and run . The first view now has One as a title.
We used viewWillAppear
and not viewDidLoad.
ViewController
is the root view controller in the navigation stack. It only loads once and stays active in the background. It will execute viewDidload
only once. To make sure we update, we use viewWillAppear
instead.
The title can be dynamic. As a simple example, We’ll place a count in the title of the navigation bar. Add the following code:
var vcCount:Int = 0{ didSet{ navigationItem.title = "Count: \(vcCount)" } }
We used the didSet
property observer feature of Swift. Any time vcCount
changes, the title changes with it. We change the count on any segue so we can increment in prepareForSegue
. Add this:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { ++vcCount }
It’s rare to not have a statement within an if
clause in a prepareForSegue
. We want any segue to increment the count, so we don’t need the if
.
We want to show the count when we load. Change the viewWillAppear
to this:
override func viewWillAppear(animated: Bool) { // navigationItem.title = "One" navigationItem.title = "Count: \(vcCount)" }
Build and run. Go back and forth in the views. The title changes every time you come back to it.
Programming the Back Button
You’ll notice once you have a title, the navigation Back button disappears, to be replaced by the previous view’s title.
The Back button reads the controller underneath the current controller for its title. You cannot set the back button title directly. Instead, you set the title of the current controller before you leave for the destination controller. If the previous view controller’s title is nil
, the button titles itself Back. Change the prepareForSegue
to this:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { ++vcCount navigationItem.title = nil }
Build and run. You have a Back button with the count:
If you wanted to add your own text to the Back button, you have to change the title of the controller below it on the navigation stack. Change prepareForSegue
to this:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { ++vcCount navigationItem.title = nil if segue.identifier == "pizza"{ navigationItem.title = "Pizza to One" } if segue.identifier == "pasta"{ navigationItem.title = "Pasta to One" } }
Before we segue to the pizza and pasta controller, we change the title
of the current controller’s navigationItem
. The Back button reads the title
of the and sets the button’s title accordingly. The viewWillAppear
method will reset the title to the count in the first view controller when we pop the Pizza or Pasta view controller. Build and Run. Select to the Pizza and Pasta buttons:
To see this happening, you can comment out this in viewWillAppear.
//navigationItem.title = "Count: \(vcCount)"
Build and Run. When you go back, the title remains:
Uncomment the line before you go on.
The Size-sensitive Back Button.
The Back button is sensitive to the space around it. The button’s title responds to not having enough space to place itself. Change the prepareForSegue
above to this:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { ++vcCount navigationItem.title = nil if segue.identifier == "pizza"{ let vc = segue.destinationViewController as UIViewController vc.navigationItem.title = "View Controller Pizza" navigationItem.title = "Pizza to One" } if segue.identifier == "pasta"{ let vc = segue.destinationViewController as UIViewController vc.navigationItem.title = "View Controller Linguine all’arrabbiata" navigationItem.title = "Pasta to One" } }
Lines 5 and 10 get the destination view controller and assign it to vc
. We dynamically send the title by vc.navigationItem.title
in lines 6 and 11. We’ve picked some long labels to test size restrictions. Set the simulator to iPad 2. Build and run. Select the Pizza button.
Go back, change the switch and select the pasta button.
In both cases, we get the title we wanted in the back button. Stop the simulator and change to an iPhone 6. Run again, change the switch for Pasta and you get something different.
We lose our custom title and we have a back button again. Now try an iPhone 4s in the simulator. Run the demo, switch to the Pasta controller and you get this:
There is only the < icon and no text for the back button. Rotate the device by pressing Command-Left Arrow:
The text re-appears with more space to place the text.
The back button is intelligent. If it has enough space, it displays the title of the previous controller. If there is not enough space, it displays Back. If there is not enough space for the word Back, it displays only the < icon.
There is an important design rule in play here that I am intentionally breaking to make the point: Keep your titles short in a navigation bar. If you keep titles short, you will have the full functionality of the back button.
The Whole Code
Downloading Code
I’m trying an new way of sharing sourcecode. The will be a .zip file for download at the the end of the lesson. It will contain sourcecode and assets only. You will have to build your own application.
Here is the source code for the lesson: NavBarDemo_Source.
Download it and unzip it. You will find two files. ViewController.Swift and Main.Storyboard. In Xcode, Open up a new single view project named NavBarDemo using Swift as the language and Universal device. Delete the ViewController.Swift and Main.Storyboard and send them to the trash can. Drag the files you unzipped to the project’s navigator. In the dialog box that appears, make sure that copy files is checked on, and finish the dialog box. You now have a working copy.
ViewController.swift
// // ViewController.swift // NavBarDemo // // Created by Steven Lipton on 3/21/15. // Copyright (c) 2015 MakeAppPie.Com. All rights reserved. // import UIKit class ViewController: UIViewController { var vcCount:Int = 0{ didSet{ navigationItem.title = "Count: \(vcCount)" } } override func viewWillAppear(animated: Bool) { // navigationItem.title = "One" navigationItem.title = "Count: \(vcCount)" } override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { ++vcCount navigationItem.title = nil if segue.identifier == "pizza"{ let vc = segue.destinationViewController as UIViewController vc.navigationItem.title = "View Controller Pizza" navigationItem.title = "Pizza to One" } if segue.identifier == "pasta"{ let vc = segue.destinationViewController as UIViewController vc.navigationItem.title = "View Controller Linguine all’arrabbiata" navigationItem.title = "Pasta to One" } } }
Leave a Reply