Navigation Component and multi backstack navigation

Anton Uryvskii
3 min readJan 20, 2021

--

You are now in the fourth part of a large story about the Navigation Component in a multi-module project. If you already know:

Then welcome to the final story about my experience with this beautiful library about a solution for iOS-like multistack navigation. Otherwise, read the three stories above first.

In addition to the Navigation Component library, Google has released several interface features called Navigation UI, which will help you connect navigation to bottomBar, Menu, and other standard components. However there are often requirements that each tab has its own stack and the current state is saved when switching between them. Unfortunately, out of the box Navigation Component and NavigationUI do not know how to do this. Support for this approach was provided by Google itself in its architecture-components-samples repository on GitHub (https://github.com/android/architecture-components-samples/tree/master/NavigationAdvancedSample). It’s basically the following:

  1. Add a FragmentContainer.
  2. Create a NavHostFragment and a graph for each tab.
  3. When tab is selected, attach the required NavHostFragment and detach the current one using FragmentManager-a transactions.

But in the course of working with this solution, I redid some points related to the specifics of the project:

  • Many applications have sign in / up flow, on boarding and other screens that should not be included in the stacks, but even in this case, everything is quite simple wraps by standard tools. Navigation between these parts can be built as usual, for example, as in the previous story.
  • In the example, all stacks are initialized immediately when the application starts. This is due to the correct operation of NavigationBottomBar and processing of Deep Links. Still I have often come across projects where deep links are not needed and the navigation bar requires customization. The project on which I tested this approach is no exception. Looking at the original NavigationExtensions file in 250 loc, I decided to throw out everything unnecessary and do lazy initialization of nav hosts, leaving only the basic functions:

Searching and initialization of target NavHost fragment:

fun obtainNavHostFragment(
fragmentManager: FragmentManager,
fragmentTag: String,
navGraphId: Int,
containerId: Int
): NavHostFragment {
// If the Nav Host fragment exists, return it
val existingFragment =
fragmentManager.findFragmentByTag(fragmentTag) as NavHostFragment?
existingFragment?.let { return it }
// Otherwise, create it and return it.
val navHostFragment = NavHostFragment.create(navGraphId)
fragmentManager.beginTransaction()
.add(containerId, navHostFragment, fragmentTag)
.commitNow()
return navHostFragment
}

NavHost Swapping:

protected fun selectTab(tab: Tab) {
val newFragment = obtainNavHostFragment(
childFragmentManager,
getFragmentTag(tabs.indexOf(tab)),
tab.graphId,
containerId
)
val fTrans = childFragmentManager.beginTransaction()
with(fTrans) {
if (selectedFragment != null) detach(selectedFragment!!)
attach(newFragment)
commitNow()
}
selectedFragment = newFragment
currentNavController = selectedFragment!!.navController
tabSelected(tab)
}

Custom implementation of “Back” press:

activity?.onBackPressedDispatcher?.addCallback(
viewLifecycleOwner,
object: OnBackPressedCallback(true){
override fun handleOnBackPressed() {
val isNavigatedUp = currentNavController.navigateUp()
if(isNavigatedUp){
return
}else{
activity?.finish()
}
}
}
)

Summary

This way we get iOS-like navigation and even better, because we have a lazy load on the stacks, navigation which is independent of controls type and less code. A nice bonus — we have a completely obvious and transparent navigation scheme that is easy to scale and modify.

Sign up to discover human stories that deepen your understanding of the world.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

Anton Uryvskii
Anton Uryvskii

No responses yet

Write a response