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:
- When UITabBarController is used as rootViewController and UINavigationController is nested, how can TabBar be displayed and hidden freely when switching pages?
- 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?
- How to customize different styles of navigation bar?
- How to make the navigation transition natural and not stiff when switching pages?
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:
- We rootViewController is UITabBarController, there are 5 UINavigationController + VC, should we do this for each corresponding next level page?
- 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!
- Create a New Group and name it BaseControllers.
- 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:
- In the first level page, add hidesBottomBarWhenPushed, although push OK, but pop is not OK;
- 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:
- Inheritance UINavigationController;
- Override pushViewController;
- 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