UINavigationController small seriesGithub Portal:

Learn UINavigationController (1) : Basics

Learn UINavigationController (2) : show and hide the TabBar at the bottom

Learn UINavigationController (3) : NavigationBar show and hide

Learn UINavigationController (4) : Custom navigation bar + Perfect transition + unified back button

One, foreword

Last time we shared the basic knowledge of UINavigationController and the display rules of the buttons on the left of the navigation bar. At the end of the article, we left a small question for you to think about how to hide tabbar when pushing from level 1 to level 2. Of course, when pop, tabbar is displayed.

We talked about a Bool variable in source code analysis. I don’t know if you have noticed it in particular, or if you have tried it yourself.

In the figure above, I have highlighted this variable, which is in UIViewController, (question 1) \color{red}{(question 1)} (question 1) how to use it?

This series imitates JINGdong. We can see that in most e-commerce apps, the navigation bar of the first-level page is customized or hidden. A push to a secondary page will use a series of defaults (color, number of left and right buttons can be customized), but will definitely be displayed; (Question 2) \color{red}{(Question 2)} (Question 2) How to control the display and hide of the navigation bar, and how to customize the navigation bar?

At the same time, we should also remember that different apps have different styles, which may be due to the different color of the navigation bar. For example, in mainstream e-commerce apps, the navigation bar may be red, while some pages are white. Other apps may display different colors or images for different module functions; However, it will be mentioned here that the transition of the navigation bar is too rigid when the user slides back, as shown below:

(QUESTION 3) \color{red}{(Question 3)} (Question 3) How to optimize the transition of the navigation bar when switching pages relatively naturally?

Ok, so to summarize the problems we encountered:

  1. When UITabBarController is used as rootViewController and UINavigationController is nested, how can TabBar be displayed and hidden freely when switching pages?
  2. Some pages need to hide the NavigationBar, some also need to show, in the page switch, how to control the NavigationBar show and hide freely?
  3. How to customize different styles of navigation bar?
  4. How to make the navigation transition natural and not stiff when switching pages?


We will learn how to deal with these problems in chapters one by one, because there will be more and more content involved. It will take too long and tiresome to finish one article. We will learn how to deal with these problems in turn in chapters, because it will take too long and tiring to finish one article. }

2. Control the display and hiding of TabBar

Now that we’ve said that in UIViewController there are hidden Bottom BarWhenpushed = true to hide when pushed to the next page, let’s try this property first, Try it in HomeViewController first, like this:

class HomeViewController: UIViewController {
    override func viewDidLoad(a) {
        super.viewDidLoad()
        title = "Home page"
        
        // If nested by UITabBarController, set this property to hide the bottom TabBar when going to the next page
        hidesBottomBarWhenPushed = true
        .
    }
    .
}
Copy the code

The overall screenshot is as follows:

Then run it:

Then we see that the TabBar is actually hidden when pushed to the secondary page, but when popped, the TabBar is not displayed again… What if, at this point, some people might say, what if I put this property on a secondary page? We can try:

  • First remove the hidden bottom BarwhenPushed code added in HomeViewController;
  • Modify the secondary page as follows:
class ViewController: UIViewController {
    
    override func viewDidLoad(a) {
        super.viewDidLoad()
        view.backgroundColor = .red
        
        title = "Secondary page"
        
        // If nested by UITabBarController, set this property to hide the bottom TabBar when going to the next page
        hidesBottomBarWhenPushed = true}}Copy the code

Run it again and you will find that there are no changes this time…. Why is that? That’s because we put the code in the wrong place, we need to put it in the init constructor! The code is as follows:

class ViewController: UIViewController {
    
    override init(nibName nibNameOrNil: String? .bundle nibBundleOrNil: Bundle?). {
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
        
        // If nested by UITabBarController, set this property to hide the bottom TabBar when going to the next page
        hidesBottomBarWhenPushed = true
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
    }
    
    override func viewDidLoad(a) {
        super.viewDidLoad()
        view.backgroundColor = .red
        
        title = "Secondary page"}}Copy the code

Then run it:

OK! When TabBar switched pages, we did solve this small problem, but we introduced a new one:

  1. We rootViewController is UITabBarController, there are 5 UINavigationController + VC, should we do this for each corresponding next level page?
  2. In a real project, all of our UIViewControllers must have a common base class: BaseViewController does not normally have more than one such base class, but if handled in the Init constructor of BaseViewController, the result will be the same as in the beginning, with push hidden and pop still not displayed. How to unify this?

Three, unified treatment

3.1 unified base class BaseViewController

First of all, we want to unify the base class, now may not be useful, but common sense we all know, will certainly encapsulate some content, these encapsulated content will continue to enrich in the subsequent article!

  1. Create a New Group and name it BaseControllers.
  2. Create New File… , select “Cocoa Touch Class” as follows, and click Finish.

We will do nothing with this base class for the moment, and then replace all ViewController inheritance we created earlier with this BaseViewController, for example:

3.2, create a subclass of UINavigationController CustomNavigationController inheritance

Let’s get this straight:

  1. In the first level page, add hidesBottomBarWhenPushed, although push OK, but pop is not OK;
  2. In the secondary page, only adding the hidden bottom bar whenPushed, Push & Pop to the init constructor is OK;

From these two, we can see that the hidesBottomBarWhenPushed attribute needs to be added to the ViewController that is not nested in the UITabBarController and can be normal only when added at initialization. When we push, The jump is actually done via the pushViewController method of UINavigationController, so our best solution is:

  1. Inheritance UINavigationController;
  2. Override pushViewController;
  3. According to the viewControllers in UINavigationController to determine whether the hidden bottom barwhenpushed attribute needs to be added;

Specific practices are as follows:

class CustomNavigationController: UINavigationController {

    override func viewDidLoad(a) {
        super.viewDidLoad()
    }
    
    // Override pushViewController without modifying the pushViewController logic
    // Just before the jump, check whether the target VC is a level 1 page or a level 2 page by using viewcontrollers.count:
    // viewcontroller. count > 0; We will add the hidden bottom barwhenpushed = true
    override func pushViewController(_ viewController: UIViewController.animated: Bool) {
        if viewControllers.count > 0 {
            viewController.hidesBottomBarWhenPushed = true
        }
        super.pushViewController(viewController, animated: animated)
    }
}
Copy the code

The diagram below:

Then, modify MainTabBarController as follows:

class MainTabBarController: UITabBarController {
    .
    func initTabBar(a) {
        let home = CustomNavigationController(rootViewController: HomeViewController())
        home.tabBarItem.title = "Home page"
        .}}Copy the code

As shown below (5 VC pages, namely the first level, are replaced) :

Restore secondary page code:

class ViewController: BaseViewController {
    override func viewDidLoad(a) {
        super.viewDidLoad()
        view.backgroundColor = .red
        
        title = "Secondary page"}}Copy the code

Finally, we run it again as follows:

Perfect! The correct control of TabBar display and hide is here. Welcome to exchange! thank you