Using the Navigation Controller in iOS iOS 12.11.2019

Introduction

Container view controllers manage the content from multiple view controllers, and each have their own approach to view hierarchies. Certain container view controllers that you may encounter include

  • Navigation controllers. Manages navigation between content view controllers.
  • Tab bar controllers. Adds a tab bar at the bottom of the interface to navigate between view controllers.
  • Split view controllers. Shows two content view controllers simultaneously in certain devices and orientations and navigates between the two in other devices or orientations.

A navigation controller manages navigation going forward and back through a hierarchy of content view controllers. The navigation controller is usually used in conjunction with a navigation bar. The navigation bar can be helpful to orient the user with a title for the scene and a back button to return to the previous scene. The navigation bar can also be a useful location for additional buttons.

The navigation controller manages its view controllers in a navigation stack, which is an array of view controllers. The navigation controller’s root view controller will be the first view controller in the navigation stack. When the navigation controller navigates to a new scene, the new view controller is added to the stack. When the user selects the back button, the current view controller is removed from the stack.

So, a Navigation Controller acts as a frame around a root view. The root view displays data while the Navigation Controller provides a navigation bar at the top of every view that can show a title and buttons.

Every Navigation Controller needs exactly one root view. By itself, a Navigation Controller and its root view does nothing more than display data. What makes the Navigation Controller useful is when the root view connects to another view through a link called a segue.

A segue consists of an identifying name and a visual link from one view to another. The first view needs a button or some other item for the user to trigger the segue and make it display the second view. Then the Navigation Controller automatically displays a Back button on the navigation bar of the second view, which allows the user to return to the first view. The only code needed to display another view is this:

performSegue(withIdentifier: "segueIdentifier", sender: self)
  1. Click the Main.storyboard file in the Navigator pane. Xcode displays the single view.
  2. Click the View Controller Scene in the Document Outline.
  3. Choose Editor > Embed In > Navigation Controller. Xcode displays a Navigation Controller in the storyboard and makes the single view the root view of the Navigation Controller.
  4. Click the Library icon to open the Object Library window.
  5. Drag and drop a View Controller from the Object Library window to the storyboard.
  6. Click View in the Document Outline under the View Controller that you just added to the storyboard. Xcode highlights the view. This view appears on the View Controller that is not connected to the Navigation Controller.
  7. Click the Attributes Inspector icon in the upper right corner of the Xcode window.
  8. Click Background popup menu and choose a color. Xcode fills the view of this newly added View Controller with a color. This color will make it easy to verify when this View Controller appears.
  9. Click the View Controller icon of the root controller, hold down the Control key, and Ctrl-drag the mouse to point inside the newly added View Controller.
  10. Release the Control key and the left mouse button. A popup menu appears.
  11. Choose Show. Xcode draws an arrow (segue) linking the root view to the newly added View Controller
  12. Click Show segue to "View Controller" in the Document Outline. Xcode highlights the segue between the two views.
  13. Choose View > Inspectors > Show Attributes Inspector, or click the Attributes Inspector icon in the upper right corner of the Xcode window.
  14. Click in the Identifier text field, type firstLink, and press ENTER.
  15. Click the ViewController.swift file in the Navigator pane.
  16. Add the following function:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    performSegue(withIdentifier: "firstLink", sender: self) 
}

The purpose of this code is to identify the segue named firstLink and follow that segue to open another view, which is the view with a different background color.

Each time you add a new View Controller to a storyboard, you need to do the following:

  1. Create a new .swift Cocoa Touch Class file and connect it to the View Controller.
  2. Create a segue link from the last View Controller in the Navigation Controller to the newly added view.
  3. Define an identifying name for this new segue link.
  4. Write Swift code in the last view’s .swift file to open the next display when triggered by user interaction such as tapping a button or the screen.

Background information

A UINavigationController maintains an array of view controllers presenting related information in a stack. When a UIViewController is on top of the stack, its view is visible.

When you initialize an instance of UINavigationController, you give it a UIViewController. This UIViewController is added to the navigation controller’s viewControllers array and becomes the navigation controller’s root view controller. The root view controller is always on the bottom of the stack.

More view controllers can be pushed on top of the UINavigationController’s stack while the application is running. These view controllers are added to the end of the viewControllers array that corresponds to the top of the stack. UINavigationController’s topViewController property keeps a reference to the view controller at the top of the stack.

When a view controller is pushed onto the stack, its view slides onscreen from the right. When the stack is popped (i.e., the last item is removed), the top view controller is removed from the stack and its view slides off to the right, exposing the view of the next view controller on the stack, which becomes the top view controller.

Every UIViewController has a navigationItem property of type UINavigationItem. However, unlike UINavigationBar, UINavigationItem is not a subclass of UIView, so it cannot appear on the screen. Instead, the navigation item supplies the navigation bar with the content it needs to draw. When a UIViewController comes to the top of a UINavigationController’s stack, the UINavigationBar uses the UIViewController’s navigationItem to configure itself.

By default, a UINavigationItem is empty. At the most basic level, a UINavigationItem has a simple title string. When a UIViewController is moved to the top of the navigation stack and its navigationItem has a valid string for its title property, the navigation bar will display that string.

A navigation item can hold more than just a title string. There are three customizable areas for each UINavigationItem: a leftBarButtonItem, a rightBarButtonItem, and a titleView. The left and right bar button items are references to instances of UIBarButtonItem, which contain the information for a button that can only be displayed on a UINavigationBar or a UIToolbar.

Passing Data to Other Views

When an app displays multiple views in a Navigation Controller, data selected or entered in one view may need to be used in another view. Since the whole purpose of object-oriented programming is to isolate data, the solution is to pass data from one view to the other.

To receive data, a view needs the following:

  • A .swift Cocoa Touch Class file connected to its View Controller.
  • Properties defined with the var keyword in this .swift file. Any data stored in a property can then be copied into any objects on the user interface connected by an IBOutlet variable.

To send data, a view needs the following in its own .swift Cocoa Touch Class file:

  • A prepare for segue function that defines a constant that represents the segue destination
  • Data assigned to properties defined by the receiving view’s .swift file

To see how to pass data from one view to another in a Navigation Controller, follow these steps:

  1. Click the Main.storyboard file in the Navigator pane. Xcode displays storyboard.
  2. Click the Library icon to open the Object Library window.
  3. Drag and drop a label anywhere on the second (colored) view.
  4. Resize the label’s width so it can display more than a single word of text.
  5. Choose Editor > Resolve Auto Layout Issues > Reset to Suggested Constraints. Xcode adds constraints to the label.
  6. Choose File > New > File. Xcode displays a list of templates.
  7. Choose Cocoa Touch Class under the iOS category and click the Next button. Another dialog appears, asking for a class name and subclass.
  8. Click in the Class text field and type SecondViewController.
  9. Click in the Subclass of popup menu and choose UIViewController.
  10. Click the Next button. Xcode asks where to store the file.
  11. Click the Create button. Xcode displays the SecondViewController.swift file in the Navigator pane.
  12. Click the Main.storyboard in the Navigator pane.
  13. Click the View Controller icon above the second view to select it.
  14. Choose View > Inspectors > Show Identity Inspector, or click the Identity Inspector icon in the upper right corner of the Xcode window.
  15. Click in the Class popup menu and choose SecondViewController. This connects the SecondViewController.swift file to the second View Controller with the colored background.
  16. Choose View > Assistant Editor > Show Assistant Editor, or click the Assistant Editor icon in the upper right corner of the Xcode window. This displays the Main.storyboard file on the left and the SecondViewController.swift file on the right.
  17. Move the mouse pointer over the label on the second view, hold down the Control key, and Ctrl-drag from the label to the SecondViewController.swift file underneath the class SecondViewController line.
  18. Release the Control key and the left mouse button. A popup window appears.
  19. Click in the Name text field and type labelDisplay. Then click the Connect button. Xcode creates an IBOutlet as follows:
@IBOutlet var labelDisplay: UILabel!

Add the following underneath this IBOutlet:

var receivedString = ""

Edit the viewDidLoad method as follows:

override func viewDidLoad() {
    super.viewDidLoad()
    labelDisplay.text = receivedString
}

This viewDidLoad method takes whatever data is stored in the receivedString property and stores it in the labelDisplay.text property so the text can appear on the label on the user interface.

Choose View > Standard Editor > Show Standard Editor, or click the Standard Editor icon in the upper right corner of the Xcode window.

Click the ViewController.swift file in the Navigator pane.

Add the following function in the ViewController.swift file:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    let nextVC = segue.destination as! SecondViewController 
    nextVC.navigationItem.title = "Second View Title" 
    nextVC.receivedString = "Passed text"
}

Modifying the appearance of the Navigation Bar

To make a Navigation Controller look more appealing, you can change the color of the navigation bar or add Bar Button Items.

Some different ways to customize the navigation bar include

  • Prompt. Displays a single line of additional text at the top of the navigation bar
  • Title. Defines the text that appears in the middle of the navigation bar
  • Back button. Changes the back button’s default text of “Back” to something more descriptive
  • Color. Defines the color of the navigation bar

Modifying text for the Back Button

let customButton = UIBarButtonItem() 
customButton.title = "New back text" 
navigationItem.backBarButtonItem = customButton

Modifying the prompt and title text

override func viewDidLoad() {
    super.viewDidLoad()
    navigationItem.prompt = "Prompt text" 
    navigationItem.title = "Title text"
}

//or

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    let nextVC = segue.destination as! SecondViewController 
    nextVC.navigationItem.prompt = "Prompt text" 
    nextVC.navigationItem.title = "Title text"
}

The tintColor property on the navigation bar (which is defined by the Navigation Controller) defines the color of the Back button text. The following code changes the Back button text to red, but you can choose any color.

navigationController?.navigationBar.tintColor = UIColor.red

The barTintColor property defines the color of the navigation bar. Keep in mind that whatever color you choose for the navigation bar should contrast with any colors defined for the Back button to make it easy to see.

navigationController?.navigationBar.barTintColor = UIColor.green

Adding Buttons to a Navigation Bar

The navigation bar always displays a Back button on all but the root view. However, you can always add more buttons on the right side of the navigation bar. Then you can connect these buttons to IBAction methods to make them actually do something.