Standalone Navigation Bar
Declaring Navigation Bar’s Independence
Most of the time, we use UINavigationBar just comes with UINavigationController. In this case, navigation controller creates our mighty bar, displays it and we can access the actual bar instance whenever we want by using navigation controller object. Also navigation controller set itself as delegate to associated navigation bar.
But how are all these navigational things managed? In fact, it has a quite logical mechanism. UINavigationBar contains an array of UINavigationItem for displaying content. According to Apple documents, UINavigationItem means;
The items to be displayed by a navigation bar when the associated view controller is visible.
For instance, whenever you pushed a view controller to a navigation controller stack, navigation controller gets navigation item of upcoming view controller and pushes this item into navigation bar’s navigation item array. Also if you pop current view controller from navigation stack, it’s navigation item will be popped from navigation bar’s navigation item array too. You should deal with navigation item of a view controller if you want to make changes on displayed navigation bar above it. The figure taken from Apple’s documentation can make clearer how this stuff works for you;
Of course all these stuff works automatically in the background most of the time, thanks to the navigation controller.
In fact, to clarify who has control over navigation bar mentioned above, if you ask who is navigation bar’s god, answer will definitely be UINavigationController.
However, there may be some times we want to break this bond. You can think that it is not necessary, even you may think that it should be avoided since it is default behavior. But let’s take a look at simplify version of a problem I have faced in real world;
You can see that the navigation bar is fading while using interactive pop gesture. Actually I think it looks cool, however it may be an undesired behavior especially your product manager expect from you a solid transition from top of the screen to bottom. In this case, we should use standalone navigation bar.
Standalone Navigation Bar
Here is the bad news for navigation controller, we will use a totally new navigation bar created separately, instead of provided by navigation controller 😌
Before start, let’s take a look current code that updates navigation bar’s appearance in the second view controller which is pushed to stack;
As you can see, we access navigation bar via navigation controller. Since we want a standalone bar, let’s hide navigation controller’s navigation bar using setNavigationBarHidden in viewWillAppear.
So, we should create a navigation bar instance. However, as I mentioned above, navigation bar without at least one navigation item means basically nothing. Then let’s create a navigation item in a new method;
Navigation item is ready to be displayed ✈️. We can create standalone navigation bar now;
To summarize what we did above, we have created a navigation bar instance first, then it is added to view controller’s view and constraints set. Finally, we have set our navigation item that contains start wars image as navigation item array to navigation bar. Let’s look at the result after putting all together and calling this method in viewDidLoad;
Woops… It seems something is going wrong around to top of screen. Status bar isn’t interested in our new bar and it remained with same color. Remember that the delegate of the navigation bar associated with navigation controller is navigation controller itself. However our lonesome navigation bar’s delegate is not set yet. Let’s dig out UINavigationControllerDelegate in Apple’s documents addressed below;
You can see that it is mostly about giving callback information about push and pop on navigation item array. However if you look at the bottom of the page, you will notice that UINavigationBarDelegate inherits from other delegate called UIBarPositioningDelegate. I think it may help us about our little status bar problem 😌. Since owner of the standalone navigation bar is view controller currently presented, let’s set it as navigation bar’s delegate and implement position method as below;
After last changes, we can see it woks;
There are still couple of problems exists. First, since we have hide navigation controller’s navigation bar in second view controller, swipe back gesture is disabled. To solve this, we will use a bit hack. Put the code below to second view controller’s viewWillAppear method and the problem solved.
Second problem is there is no back button on the left of the navigation bar. We have to add this bar button ourselves. You can simply add a bar button with selector to the navigation item like below;
Call this method with passing navigation item as parameter in where you initialized it. Then back button will work fine.
Thats all. As a result of the all stuff above, we have a relatively better swipe transition from top to bottom between these two view controllers;
Final Words
At the end of the story, we have learned some basics of the UINavigationBar and implemented it as standalone object. Although all codes presented above enough for our little demo project, it would be wiser putting them in a class responsible from creation like factory or builder to initialize it easily when needed. Generally, I use standalone navigation bar in view controllers that contains custom transitions applied not only on view but also on navigation bar.
What do you think about using standalone navigation bar? Do you think that it is necessary to use in situations like above or similar behavior can be implementable with navigation bar associated with navigation controller ? Or do you prefer a customized UIView object instead of standalone navigation bar?
Have a nice day!