Last year, I read an article by the technical team of Meituan-Dianping about the transition solutions and best practices of the navigation bar in iOS system. The transformation of the navigation bar in the article was very interesting. Recently, I tried to write some codes to practice my skills.

The address of the project: DoubleNavigationController

This library has not been tested in a real project and there are still many things that are not perfect or do not meet the business needs. Welcome to issue or PR.

A little doubt

  • Why did you develop this library?

The UINavigationController is described in the Apple documentation as follows:

A navigation controller is a container view controller that manages one or more child view controllers in a navigation interface.

That is, UINavigationController acts as the manager of UIViewController, so its NavigationBar should not be subordinate to any ViewController. But most UI designers don’t understand what Apple’s design is all about, so there’s a common scenario in business where multiple ViewControllers that logically should belong to the same NavigationController have different NavigationBar styles.

Different page developers can only see the convenience of their own development, the understanding of UINavigationController is not enough, and the NavigationBar style is changed everywhere. In the process of page transitions, NavigationBar has various uncontrollable problems. This problem becomes even more acute when the App supports routing because the jump relationships between pages can be very complex and unpredictable.

DoubleNavigationController solved is the problem, let developers free to modify the NavigationBar style, and don’t have to worry about after return to stack the ViewController NavigationBar style has also been modified. In simple terms, our changes to the NavigationBar no longer affect the existing page styles in the stack, but only the new pages that we Push later.

  • Why not design it so that it doesn’t affect either existing page styles in the stack or new pages?

Here to tell me the two design ideas of the DoubleNavigationController “first come, first served”, “who use changes”.

“First come, first served”

The page style that appears first should not be affected by the page that appears later. Users in the use process to see the first page of A style, from A page to jump to page B, then page B, navigation style is different from A page, when the user returns to A page, from the normal logic, the user wants to see A page navigation bar should be met before or style, should not be changed under the influence of B.

“Whoever uses it modifies it”

Continuing with the above scenario, the user goes from page A to page B, and then jumps from page B to page C. In the previous scenario, we know that page B has modified the navigation bar style to make it different from page A. When we jump to page C, there are two possibilities as follows:

  1. Page C also makes changes to the navigation bar style properties that were just modified on page B.

  2. Page C does not modify the navigation bar style properties that were just modified on page B.

In the first case, we can easily determine that the navigation style of the C page should be the style of the C page itself. So in case 2, what should the navigation bar of the C page look like?

Consider the following three scenarios: Same as page A? Same configuration as UIAppearance, right? Same as page B, right?

Is the navigation bar of page C the same as page A?

This scenario is logically wrong, because a C page should not care about its previous page style. As shown in the figure below, assuming that page B has two jump paths A1 and A2, there are two possible styles of page C. It is believed that the design of most APPS will not have the situation of “one page, two UI”.

C Is the navigation bar configured the same as UIAppearance?

There are also two problems with keeping the C page consistent with the UIAppearance configuration. One is what if the user has not configured UIAppearance?

A bigger problem is that this seems to break apple’s definition of UINavigationController, which logically makes the NavigationBar a separate entity held by a single page, in which case it’s better to hide the NavigationBar, Each page is implemented with its own navigation bar for easier maintenance.

Is the navigation bar on page C the same as page B?

Keep it the same as page B. At first glance, this is the same as “Page A?” The solutions may seem similar, but in fact the two solutions are fundamentally different. A better way to say “the same as page B” would be “the same as the most recent user modification of the navigation bar”. In other words, page C only needs to focus on the navigation bar itself, and does not need to focus on who modified the navigation bar, so as to meet the above design concept of “who uses the modification”.

implementation

For the implementation of this library, I refer to the navigation bar transition solutions and best practices in iOS system in this article by Meituan Dianping.

Hide the original NavigationBar and add a fake NavigationBar during the transition. When the transition is over, delete the fake NavigationBar and restore the original NavigationBar. This process can be completed by Swizzle. Each ViewController only needs to care about its own style.

DoubleNavigationController core of the solution and the article mentioned is the same, but on the way and details may be related to the article mentioned are not the same, in addition, there are some implementation details in Meituan comments on this article did not reveal too much.

A few details

Detail 1: choose the direct DoubleNavigationController NSKeyedArchiver to replicate a FakeNavigationBar without custom UIView.

Detail 2: Sometimes a page’s NavigationBar may change dynamically during user interaction, so we need to record every change to the NavigationBar look and feel and update the FakeNavigationBar look and feel as appropriate.

Detail 3: Since UIAppearance changes the appearance of the object after the UIView is added to the view tree, you need to duplicate the UIAppearance property with the current navigationBar before using the FakeNavigationBar. Reference: iOS UIAppearance Exploration — HyanCat’s

example

Clone the repository, go to the Example directory and execute Pod Install to run a demo.

usage

Through the implementation in the ViewController dbn_configNavigationController this method to customize the navigation bar style.

- (void)dbn_configNavigationController:(UINavigationController *)navigationController {
    [navigationController setNavigationBarHidden:NO animated:NO];
    navigationController.navigationBar.barTintColor = [UIColor whiteColor];
    navigationController.navigationBar.tintColor = [UIColor purpleColor];
    navigationController.navigationBar.titleTextAttributes = @{NSFontAttributeName: [UIFont systemFontOfSize:20], NSForegroundColorAttributeName: [UIColor redColor]};
}

- (void)dbn_configNavigationItem:(UINavigationItem *)navigationItem {
    UIBarButtonItem *btnItem = [[UIBarButtonItem alloc] initWithTitle:@"Next" style:UIBarButtonItemStylePlain target:self action:@selector(eventFromButton:)];
    navigationItem.rightBarButtonItem = btnItem;
    navigationItem.title = @"Hello";
}
Copy the code

You can also use the dbn_performBatchUpdates: method to update the navigation bar style over time.

[self dbn_performBatchUpdates:^(UINavigationController * _Nullable navigationController) {
    if(navigationController) { navigationController.navigationBar.tintColor = [UIColor purpleColor]; }}];Copy the code

The address of the project: DoubleNavigationController

Other Open Source works

TinyPart – modularity framework making | the Denver nuggets

FastKV – iOS high performance, high real time capability of the key – value persistence component lot | the Denver nuggets

Coolog – extensible log frame making | the Denver nuggets

reference

Navigation bar transitions solutions and best practices in iOS

UIKit UIAppearance – APPLE

IOS UIAppearance Exploration — HyanCat’s