UINavigationController

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. (Note that while this view controller is referred to as the navigation controller’s root view controller, UINavigationController does not have a rootViewController property.)

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. Figure 12.3 shows a navigation controller with two view controllers. The view of the topViewController is what the user sees.

Figure 12.3  UINavigationController’s stack

UINavigationController’s stack

UINavigationController is a subclass of UIViewController, so it has a view of its own. Its view always has two subviews: a UINavigationBar and the view of topViewController (Figure 12.4).

Figure 12.4  A UINavigationController’s view

A UINavigationController’s view

In this chapter, you will add a UINavigationController to the LootLogger application and make the ItemsViewController the UINavigationController’s root view controller. The DetailViewController will be pushed onto the UINavigationController’s stack when an Item is selected. This view controller will allow the user to view and edit the properties of an Item selected from the table view of ItemsViewController. The object diagram for the updated LootLogger application is shown in Figure 12.5.

Figure 12.5  LootLogger object diagram

LootLogger object diagram

This application is getting fairly large, as you can see. Fortunately, view controllers and UINavigationController know how to deal with the complex relationships in this object diagram. When writing iOS applications, it is important to treat each UIViewController as its own little world. The stuff that has already been implemented in Cocoa Touch will do the heavy lifting.

Reopen the LootLogger project. You are going to begin by giving LootLogger a navigation controller. The only requirements for using a UINavigationController are that you give it a root view controller and add its view to the window.

Open Main.storyboard and select the Items View Controller. Then, from the Editor menu, choose Embed InNavigation Controller (this can also be done from the LootLogger object diagram button in the bottom right). This will set the ItemsViewController to be the root view controller of a UINavigationController. It will also update the storyboard to set the Navigation Controller as the initial view controller.

Your Detail View Controller interface may have misplaced views now that it is contained within a navigation controller. If it does, select the stack view and click the Update Frames button in the Auto Layout constraint menu.

Build and run the application and … the application crashes. What is happening? You previously created a contract with the SceneDelegate that an instance of ItemsViewController would be the rootViewController of the window:

    let itemsController = window!.rootViewController as! ItemsViewController

You have now broken this contract by embedding the ItemsViewController in a UINavigationController. You need to update the contract.

Open SceneDelegate.swift (if Xcode has not opened it for you) and update scene(_:willConnectTo:options:) to reflect the new view controller hierarchy.

Listing 12.1  Updating the SceneDelegate (SceneDelegate.swift)

func scene(_ scene: UIScene,
           willConnectTo session: UISceneSession,
           options connectionOptions: UIScene.ConnectionOptions) {
    guard let _ = (scene as? UIWindowScene) else { return }

    // Create an ItemStore
    let itemStore = ItemStore()

    // Access the ItemsViewController and set its item store
    let itemsController = window!.rootViewController as! ItemsViewController
    let navController = window!.rootViewController as! UINavigationController
    let itemsController = navController.topViewController as! ItemsViewController
    itemsController.itemStore = itemStore
}

Build and run the application again. LootLogger works again and has a very nice, if totally empty, UINavigationBar at the top of the screen (Figure 12.6).

Figure 12.6  LootLogger with an empty navigation bar

LootLogger with an empty navigation bar

Notice how the screen adjusted to fit ItemsViewController’s view as well as the new navigation bar. UINavigationController did this for you: While the view of the ItemsViewController actually underlaps the navigation bar, UINavigationController added padding to the top so that everything fits nicely. This is because the safe area insets for the view controller’s view are adjusted.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset