You are now in the fourth part of a great article about Navigation Component in a multi-module project. If you already know:
-
How Safe Args plugin works and what it does
How can you build working with the Navigation Component in a multi-module project
Then welcome to the final part of the story about my experience with this wonderful library - about the solution for iOS-like multistack navigation.
You can see how it all works here
If you do not know, then go out and come in normally read the three articles above first.
In addition to the Navigation Component library, Google has released several frontend add-ons called NavigationUI to help you connect navigation to BottomBar, Menu, and other standard components. But often there are requirements that each tab has its own stack and the current states are preserved when switching between them. Unfortunately, out of the box, Navigation Component and NavigationUI don't do that.
Support for this approach was provided by Google themselves in their architecture-components-samples repository on GitHub ( https://github.com/android/architecture-components-samples/tree/master/NavigationAdvancedSample ). Its essence is simple:
Add FragmentContainer.
NavHostFragment .
NavHostFragment FragmentManager-a.
, :
. NavigationBottomBar Deep Link-. , deep link- . , — . NavigationExtensions 250 loc, lazy- NavHost-, :
/ NavHost-:
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-:
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)
}
“Back”:
activity?.onBackPressedDispatcher?.addCallback(
viewLifecycleOwner,
object: OnBackPressedCallback(true){
override fun handleOnBackPressed() {
val isNavigatedUp = currentNavController.navigateUp()
if(isNavigatedUp){
return
}else{
activity?.finish()
}
}
}
)
iOS-like , lazy- . — , .