One, foreword

In the previous chapter, we copied the bottom navigation bar of JINGdong, showing 5 pages (UIViewController). Its function can be understood as switching between pages. Each page belongs to the first level page. And level 1 page just some attract the user’s general flow of main entrance, the function of the actual page is through the primary entrance to navigate to the next level or at a deeper level of the page (from the user’s perspective, the core important pages is no more than 3, otherwise the level too deep, not interested users might continue to point, Except for “Confirm order” and “Pay” pages).

Switching between n-level pages no longer involves the bottom navigation controller, which doesn’t do that; In iOS, the specific function of navigation between pages is the UINavigationController, which we will learn today. It can realize the entry and exit between different pages.

2. NavigationController (UINavigationController)

The navigation controller is responsible for page switching. Again, let’s take a look at the official source code comment:

UINavigationController manages a stack of view controllers and a navigation bar.

A navigation controller manages a set of ViewControllers as a “stack” of data structures and has its own navigation bar.

It performs horizontal view transitions for pushed and popped views while keeping the navigation bar in sync.

By default, the transition animation for push (to the next page) and POP (to the previous page) is a pan and the navigation controller keeps the navigation bar in sync.

If you think the above comments can’t understand it doesn’t matter, I’ll analysis, know a friend can directly jump down a section (not recommended, some details “old driver” does not necessarily grasp -_ – | | |). Now let’s look at UIKit. UINavigationController source code, to understand its internal core objects and methods.

2.1 UINavigationController analysis

Essential notes…..

@available(iOS 2.0.*)
open class UINavigationController : UIViewController {
    // The constructor requires a UIViewController as the root view controller
    // When initialized, it will put this UIViewController on the stack as a push without animation
    // This UIViewController will be the first view controller on the stack
    public init(rootViewController: UIViewController) 
    
    // By default, pan animation is used to go to the next page, if the current page is already at the top of the stack, there is no effect
    open func pushViewController(_ viewController: UIViewController.animated: Bool) 

    // There are three ways to return to the page:
    // 1. Go back to the previous page: where did it come from
    open func popViewController(animated: Bool) -> UIViewController? 
    // 2. Return to the specified page: You can use this method to return to the previous page, or directly return to the root page
    // In the case of a return to the specified page, all pages on the stack above that page are unstacked and destroyed (the unstacked pages are not visible)
    open func popToViewController(_ viewController: UIViewController.animated: Bool)- > [UIViewController]? 
    // return to the first page
    open func popToRootViewController(animated: Bool)- > [UIViewController]? 
    
    // The page in the current stack can be traversed by:
    // 1. pop to return to the page we want to return to
    // 2.
    open var viewControllers: [UIViewController] 
    
    @available(iOS 7.0.*)
    // There are no English annotations for this, but we all use it
    // we also saw that it was introduced after 7.0, and its function is :(right) slide back to the previous level
    // Because the iPhone screen is getting bigger and bigger, it always makes the user click the "back" button to go back to the previous level, which is not a good experience
    open var interactivePopGestureRecognizer: UIGestureRecognizer? { get }
    
    // The navigation bar manages navigationItems, as well as stacks (why?).
    // Because each VC corresponds to a navigationItem
    open var navigationBar: UINavigationBar { get } 
    
    @available(iOS 3.0.*)
    // Tool bar containing title and image
    open var toolbar: UIToolbar! { get }
    
    // See for yourself
    .
}
Copy the code

All the methods and members listed above will be used in the future, and we will deal with them frequently. However, similar to UITabBarController, we will deal with them only once. Why? Because generally we will be encapsulated in the base class, unified management by the base class, if each page is managed by itself, it is very easy to mess up (Apple is very confused about this), and I share with you, are through practice to tell you to avoid the final result of the pit.

2.2. Extend UINavigationController analysis

extension UIViewController {
    // You can create your own navigation bar appearance (left and right buttons, title, text, image, color and transparency)
    open var navigationItem: UINavigationItem { get } 
    // This property defaults to Swift: false/OC: NO, but this property is useful when encountering UITabBarController
    open var hidesBottomBarWhenPushed: Bool 
    // We push/pop via navigationController
    open var navigationController: UINavigationController? { get}}Copy the code

2.3 Navigation bar elements: UINavigationItem analysis

We can analyze it with the following picture:

@available(iOS 2.0.*)
open class UINavigationItem : NSObject.NSCoding {
    // Title, nil by default, at the top of the UI hierarchy
    // You can run the following command to View the hierarchy of the View: Debug View Hierachy
    open var title: String?
    // You can customize the title view (for example, to put an image) only if it is at the top of the UI
    open var titleView: UIView?

    // Return key (left button)
    open var backBarButtonItem: UIBarButtonItem?
    
    // leftBarButtonItems and rightBarButtonItems, which used to be a single button, now manage a set of buttons;
    // These two correspond to the first element in each array
    @available(iOS 5.0.*)
    / / the left button
    open var leftBarButtonItems: [UIBarButtonItem]?

    @available(iOS 5.0.*)
    / / right button
    open var rightBarButtonItems: [UIBarButtonItem]?
}
Copy the code

The main is the above elements, if you do not have any doubts here, so I am very confused! Why? Don’t you see that there are two elements that control the “left button”? Respectively is:

  • BackBarButtonItem;
  • LeftBarButtonItem;


What the authorities don’t say is that we all know the truth through practice: \color{red}{official does not say, we are all through practice to arrive at the truth:}

Premise: previousVC is the previous page, nextVC is the next page, when a push occurs, there are the following rules:

  1. If nextVC’s leftBarButtonItem! The nextVC specified leftBarButtonItem is displayed to the left of the navigationBar;
  2. If nextVC’s leftBarButtonItem == nil, previousVC’s backBarButtonItem! = nil, the backBarButtonItem specified by previousVC will be displayed to the left of navigationBar;
  3. If both are nil then:
  • 3.1. The navigationItem nextVC. HidesBackButton = YES, then navigationBar will hide button on the left;
  • Otherwise, the default return button provided by the system will be displayed on the left side of navigationBar;

We find from the above rules:

  1. LeftBarButtonItem has a higher priority than backBarButtonItem;
  2. BackBarButtonItem is from the previous page, if the current VC is the first page, then it does not have the previous page, so there is no backBarButtonItem;
  3. The leftBarButtonItem is from the current page and has nothing to do with the previous page, so if the current VC is the first page, it would be weird to set the leftBarButtonItem;

Therefore, please pay attention to the above left button rule, do not set at the same time, although the priority does not show two buttons, but your display logic may be different!

With all this analysis out of the way, let’s summarize with a big picture:

3. Use of UINavigationController

3.1. Method of use

It’s very easy to use and escape not open mode, namely the window. The rootViewController has the following three Settings:

  1. Direct setting;
/ / in the AppDelegate window? .rootViewController = UINavigationController(rootViewController: XXXViewController())Copy the code
  1. UITabBarController nested UINavigationController;
/ / in the AppDelegate window? .rootViewController = MainTabBarController() // MainTabBarController let XXX = UINavigationController(rootViewController: XXXViewController()) xxx.tabBarItem.title = "xxx" viewControllers = [xxx, ......]Copy the code
  1. UINavigationController nested UITabBarController (possibly nested UINavigationController, similar to the second type);
/ / in the AppDelegate window? .rootViewController = UINavigationController(rootViewController: MainTabBarController()) // Let XXX = UINavigationController(rootViewController: XXXViewController()) xxx.tabBarItem.title = "xxx" viewControllers = [xxx, ......]Copy the code

Through the above way, we can find that the common pattern is either the first or the second.

Actual combat out of truth

Based on our previous example, we use the second approach.

  • The simple transformation is as follows

  • Modify HomeViewController

  • Running simulator

The navigation bar (with the title) is now available. Note that since iOS 7.0, the navigation bar has been changed to a flat style, so it has become translucent!

3.3 page jump push & Pop

  • Modify our HomeViewController

  • Click label and push to the next page

  • After the jump is stable, see the following figure

Four,

In the next article, we’ll look at actual scenarios and requirements (as you can see from the last image in the previous section, tabbar still shows up at the bottom of a push to a lower page, although a few apps do this, but most apps hide it). The UITabBarController and UINavigationController are combined to describe how I configure in the actual work.