How to set up Navigation Component with Navigation Drawer in Android?

前端 未结 1 1829
暗喜
暗喜 2021-02-05 20:11

How do I set up navigation component with navigation drawer? How do I use it in my app?

Can everything be done with one Activity?

How do I handle toolbar visibi

相关标签:
1条回答
  • 2021-02-05 20:56

    How do I set up navigation component with navigation drawer?

    How do I use it in my app?

    The navigation drawer set up differs a little when it comes to Navigation component.

    Note, if you create a new app with drawer navigation, the current tutorial is not needed. However I'm going to explain some things that might look strange around here and if you decide to add a drawer at a later stage of the app

    First, you need to set up your activity_main.xml and MainActivity to be ready for the Navigation Architecture:

    <?xml version="1.0" encoding="utf-8"?>
    <androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/drawer_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fitsSystemWindows="true"
        tools:openDrawer="start">
    
        <include
            layout="@layout/app_bar_main"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    
        <com.google.android.material.navigation.NavigationView
            android:id="@+id/nav_view"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_gravity="start"
            android:fitsSystemWindows="true"
            app:headerLayout="@layout/nav_header_main"
            app:menu="@menu/activity_main_drawer" />
    
    </androidx.drawerlayout.widget.DrawerLayout>
    

    where app_bar_main is just:

    <?xml version="1.0" encoding="utf-8"?>
    <androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    
        <com.google.android.material.appbar.AppBarLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:theme="@style/AppTheme.AppBarOverlay">
    
            <androidx.appcompat.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                android:background="?attr/colorPrimary"
                app:popupTheme="@style/AppTheme.PopupOverlay" />
    
        </com.google.android.material.appbar.AppBarLayout>
    
        <include layout="@layout/content_main" />
    
    </androidx.coordinatorlayout.widget.CoordinatorLayout>
    

    And the content_main is where your fragments are going to be held:

    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"
        tools:showIn="@layout/app_bar_main">
    
        <fragment
            android:id="@+id/nav_host_fragment"
            android:name="androidx.navigation.fragment.NavHostFragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:defaultNavHost="true"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:navGraph="@navigation/mobile_navigation" />
    </androidx.constraintlayout.widget.ConstraintLayout>
    

    Things you should know: The activity mustn't have a AppBar set on AndroidManifest.xml:

    android:theme="@style/AppTheme.NoActionBar"
    

    If you notice app:menu="@menu/activity_main_drawer" in the NavigationView tag, the fragment names should be the same that they are inside the mobile_navigation.xml:

    <group android:checkableBehavior="single">
            <item
                android:id="@+id/homeFragment"
                android:icon="@drawable/ic_menu_camera"
                android:title="@string/menu_home" />
            <item
                android:id="@+id/galleryFragment"
                android:icon="@drawable/ic_menu_gallery"
                android:title="@string/menu_gallery" />
            <item
                android:id="@+id/slideshowFragment"
                android:icon="@drawable/ic_menu_slideshow"
                android:title="@string/menu_slideshow" />
            <item
                android:id="@+id/toolsFragment"
                android:icon="@drawable/ic_menu_manage"
                android:title="@string/menu_tools" />
        </group>
    
        <item android:title="Communicate">
            <menu>
                <item
                    android:id="@+id/shareFragment"
                    android:icon="@drawable/ic_menu_share"
                    android:title="@string/menu_share" />
                <item
                    android:id="@+id/sendFragment"
                    android:icon="@drawable/ic_menu_send"
                    android:title="@string/menu_send" />
            </menu>
        </item>
    
    </menu>
    

    This way, with what is going to be explained below there will be no need to call for onCreateOptionsMenu to detect the clicks. Android team has already solved that for us. Follow below.

    Until now, this doesn't differ too much from the usual drawer set up we actually do. But, there are some configurations we would need to do in the logic part of the app. So let's open MainActivity.kt. First you will need these:

      private var appBarConfiguration: AppBarConfiguration? = null
      private var drawerLayout: DrawerLayout? = null
      private var toolbar: Toolbar? = null
      private var navController: NavController? = null
    

    After that in your onCreate method:

    override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
            toolbar = findViewById(R.id.toolbar)
            setSupportActionBar(toolbar) //set the toolbar
    
            drawerLayout = findViewById(R.id.drawer_layout)
            val navView: NavigationView = findViewById(R.id.nav_view)
            navController = findNavController(R.id.nav_host_fragment)
            appBarConfiguration = AppBarConfiguration(
                setOf(
                    R.id.homeFragment,
                    R.id.galleryFragment,
                    R.id.slideShowFragment,
                    R.id.toolsFragment,
                    R.id.shareFragment,
                    R.id.sendFragment,
                    R.id.loginFragment,
                    R.id.phoneConfirmationFragment
                ), drawerLayout
            )
    
            setupActionBarWithNavController(navController!!, appBarConfiguration!!) //the most important part
            navView.setupWithNavController(navController!!) //the second most important part
    
          //other things unrelated
        }
    

    Let's see what's going on here:

    First you would need a reference to the navController. The AppBarConfiguration is just a class which holds the fragments that are going to be opened as top level destinations. Which means that the fragment which is going to be opened after them would release the current one from the fragment back stack. It's important to tell to the AppBarConfiguration that we have a drawer also (passed as a parameter in the constructor).

    Down below you would have a method called onSupportNavigateUp():

    override fun onSupportNavigateUp(): Boolean {
            val navController = findNavController(R.id.nav_host_fragment)
            return navController.navigateUp(appBarConfiguration!!) || super.onSupportNavigateUp()
        }
    

    This method has to do with the up back button. But you won't need it too much if you have drawer navigation. This really comes in handy when you have a lot of fragments added on the backstack (or at least two).

    Can everything be done with one Activity?

    Yes, definitely! but still it requires a little bit more work when it comes to conditional navigation. Like when you want to show fragments which are not part of your drawer app. But still Google has done a huge progress with it. You can refer to conditional navigation here.

    How do I handle toolbar visibility with just one Activity and fragments which have a dynamic toolbar visibility. Also, there are fragments which I need to close the drawer and make it inaccessible.

    You can use addOnDestinationChangedListener from the navController:

    navController.addOnDestinationChangedListener { _, destination, _ ->
                when (destination.id) {
                    R.id.loginFragment, R.id.registerFragment, R.id.phoneConfirmationFragment -> {
                        toolbar?.visibility = View.GONE
                        drawerLayout?.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)
                    }
                    else -> {
                        toolbar?.visibility = View.VISIBLE
                        drawerLayout?.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED)
                    }
                }
            }
    

    Now you have a drawer and navigation component on your app.

    0 讨论(0)
提交回复
热议问题