Android Jetpack Navigation with ViewPager and TabLayout

前端 未结 5 807
面向向阳花
面向向阳花 2020-12-13 10:09

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

5条回答
  •  隐瞒了意图╮
    2020-12-13 10:23

    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
    
        /*
            

提交回复
热议问题