Saturday, July 27, 2019

Introduction to UINavigationController

What is it?


A navigation controller is a container view controller which manages one or more child view controllers in a navigation interface. The iOS's Settings app is an example of navigation controller.



The below image shows the objects managed by a navigation controller. It stores child view controllers in an array. Pushing a view controller to the array make the view controller's view presented. The last view controller in the array or stack displays over the others.



Why use it?


It provides a simple way to navigate between the view controllers with a pre-defined navigation interface. For example, it has many ways to present a child view controller and a navigation bar consisted of a back button to go to the previous view controller.


How to do it?


I have MyCalculator app with a Settings page as shown in the image below.



1). Embed the view controller in a navigation controller


Below is SettingsViewController defined in the Interface Builder (IB).


Click on the view controller and select Editor menu then Embed In > Navigation Controller. It then would look like this:



2). SettingsViewController.swift


import UIKit

class SettingsViewController: UITableViewController {
    
    typealias Item = (cellLabel: String, vcId: String?)
    
    private var items: [Item] = [
        (cellLabel: "Themes", vcId: "vcTheme"),
        (cellLabel: "Decimal Places", vcId: "vcDecimalPlaces"),
        (cellLabel: "Decimal Notation", vcId: "vcDecimalNotation"),
        (cellLabel: "Disable Auto-Lock", vcId:  nil)
    ]

    private var tapGestureRecognizer = UITapGestureRecognizer()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        tableView.register(UINib(nibName: "SwitchTableViewCell", bundle: nil), forCellReuseIdentifier: "tbcSwitch")
        tableView.addGestureRecognizer(tapGestureRecognizer)
        tapGestureRecognizer.addTarget(self, action: #selector(tapGestureHandler(_:)))
        
        let closeButton = UIBarButtonItem(title: "Close", style: .done, target: self, action: #selector(closeButtonHandler(_:)))
        navigationController?.navigationBar.topItem?.rightBarButtonItem = closeButton
    }
    
    @objc public func closeButtonHandler(_ sender:UIBarButtonItem) {
        dismiss(animated: true, completion: {})
    }
    
    @objc public func tapGestureHandler(_ sender: UITapGestureRecognizer) {
        let tappedPoint = sender.location(in: tableView)
        if let indexPath = tableView.indexPathForRow(at: tappedPoint) {
            let item = items[indexPath.row]
            if let vcId = item.vcId {
                let vc = storyboard?.instantiateViewController(withIdentifier: vcId)
                vc?.title = item.cellLabel
                navigationController?.pushViewController(vc!, animated: true)
            }
        }
    }

    ...

    // Required tableView() methods 

}
    

I'm using TapGestureRecognizer to detect the selected row in the Settings page and then present the corresponding view controller.

The items variable stores identifiers of the child view controllers designed in the Interface Builder. The selected identifier is used to instantiate the corresponding view controller and present it, by pushing it to the navigation controller's array.

navigationController?.pushViewController(vc!, animated: true)
    


3). Add action to the Settings button/icon in the home page


Suppose I have ViewController for the home page designed in the Interface Builder and its file named ViewController.swift. Control-drag the Settings button in the ViewController from the Storyboard to the ViewController.swift file and create an action connection.

    @IBAction func settingsButtonTouched(_ sender: SettingsButton) {
        present(settingsViewController, animated: true, completion: {})
    }    

After that, add a variable to the ViewController class as following:

    private var settingsViewController:UIViewController!    
    

Then, initialize it in viewDidLoad() method:
    
    settingsViewController = storyboard?.instantiateViewController(withIdentifier: "vcNavigation") as! UINavigationController
    

Note that we present the SettingsViewController from the home page, not its navigation controller. The navigation controller, as its name implied, just navigates the child view controllers of the SettingsViewController.





References


No comments:

Post a Comment