For a new app i use Jetpack Navigation Library to implement proper back navigation. The first level of navigation is a navigation drawer which works fine with jetpack naviga
How you implement appbar navigation changes your implementation. If you wish to use navigation from page to detail, it's using same fragmentManager the main NavHost fragment uses. It's like going to detail fragment/activity.
Home, Dashboard and Notification have their own graphs so they can open their child fragments while Login fragment belongs to main nav graph so it opens it's fragment as detail fragment.
This implementation requires main NavHostFragment in a fragment or MainActivity.
Layouts
activity_main.xml
As of now androidx.fragment.app.FragmentContainerView crashes with appbar navigation, so use fragment if you encounter navController not found error
fragment_main.xml
Fragments for ViewPager2 that have NavHostFragment, only add one, others have the same layout as this one except app:navGraph="@navigation/nav_graph_home" with their own graphs.
fragment_nav_host_home.xml
Nothing special with other fragments, skipped them, i added link for full sample and other navigation component examples if you are interested.
Navivgation Graphs
Main nav graph, nav_graph.xml
And one of the nav graph for pages of ViewPager2, others are same.
nav_graph_home.xml
Important thing with ViewPager nav graphs is to use fragment on screen instead of NavHost fragment, you need otherwise set navigation with
if (navController!!.currentDestination == null || navController!!.currentDestination!!.id == navController!!.graph.startDestination) {
navController?.navigate(R.id.homeFragment1)
}
in NavHost fragments when fragment's navHost is attached.
MainActivity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
listenBackStackChange()
}
private fun listenBackStackChange() {
// Get NavHostFragment
val navHostFragment =
supportFragmentManager.findFragmentById(R.id.main_nav_host_fragment)
// ChildFragmentManager of NavHostFragment
val navHostChildFragmentManager = navHostFragment?.childFragmentManager
navHostChildFragmentManager?.addOnBackStackChangedListener {
val backStackEntryCount = navHostChildFragmentManager.backStackEntryCount
val fragments = navHostChildFragmentManager.fragments
Toast.makeText(
this,
"Main graph backStackEntryCount: $backStackEntryCount, fragments: $fragments",
Toast.LENGTH_SHORT
).show()
}
}
}
listenBackStackChange function is just to observe how main fragment stack and fragment change, it has only observational purpose, remove it if not needed.
Adapter for ViewPager2
class ChildFragmentStateAdapter(private val fragment: Fragment) :
FragmentStateAdapter(fragment) {
override fun getItemCount(): Int = 4
override fun createFragment(position: Int): Fragment {
return when (position) {
0 -> HomeNavHostFragment()
1 -> DashBoardNavHostFragment()
2 -> NotificationHostFragment()
else -> LoginFragment1()
}
}
}
Fragments with HostFragment have no appbar navigation since it's not implemented in this example.
MainFragment
class MainFragment : BaseDataBindingFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// TabLayout
val tabLayout = dataBinding.tabLayout
// ViewPager2
val viewPager = dataBinding.viewPager
/*