So I’ve just done my first stream on Twitch, recreating an old app of mine, Dota Soundboard. During it, I found lots of confusion with setting up the navigation drawer.
Of course there was the old way with massive chunks of boilerplate, which is what I resorted to on stream until I could replace it later.
Why did I do this? Because the documentation for doing the modern navigation drawer isn’t great. So I’m hoping that this article will set that straight once and for all.
By the way, if you’re interested in a mix of programming, Tekken, and Dota content on stream, follow me on Twitch @therealpandakun.
Create your Fragments
Navigation components work through fragments. You need your home fragment, and any fragments you intend to navigate from the home fragment.
I’m gonna assume you already know how to make fragments so I’m not gonna go into detail there.
Create your menu xml
<menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/heroes_page_fragment" android:title="@string/nav_heroes" /> <item android:id="@+id/settings_page_fragment" android:title="@string/nav_settings" /> </menu>
Create an xml menu under res/menu. You don’t need your home fragment here. These are the menu items you want to have in your drawer.
Create the nav graph xmlCreate an xml navigation under res/navigation. I’ve named this one nav_graph.xml
<navigation xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/nav_graph" app:startDestination="@id/home_page_fragment"> <fragment android:id="@+id/home_page_fragment" android:name="com.ericdecanini.dotasoundboard.HomeFragment"> <action android:id="@+id/action_home_to_heroes" app:destination="@id/heroes_page_fragment" /> </fragment> <fragment android:id="@+id/heroes_page_fragment" android:name="com.ericdecanini.dotasoundboard.HeroesFragment" /> </navigation>
This is your nav graph. This sets out the navigation journey your app follows. In this case, we start at the home fragment which includes the action to go to the heroes page.
What’s important here is that the ids of the fragments here match the ids of the menu items you set out earlier. After we set it up later, this will let the system make the link between the menu items and the fragments.
Write your activity xml
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/drawerLayout" android:layout_width="match_parent" android:layout_height="match_parent"> <androidx.fragment.app.FragmentContainerView 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:navGraph="@navigation/nav_graph" /> <com.google.android.material.navigation.NavigationView android:id="@+id/navView" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="start" android:fitsSystemWindows="true" app:menu="@menu/menu_navigation" /> </androidx.drawerlayout.widget.DrawerLayout>
At minimum, you need to have a DrawerLayout which has a FragmentContainerView and a NavigationView. As you might guess, the FragmentContainerView is where the content of your fragments is gonna be, and the NavigationView is the drawer.
I could explain them all here but just look at the attributes above with the app
namespace, those are the important bits, and quite frankly, self-explanatory.
See below if you want a version of this with a custom toolbar.
Setup the Navigation Drawer in code
private lateinit var appBarConfiguration: AppBarConfiguration private fun setupNavigationDrawer() { val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment val navController = navHostFragment.navController navView.setupWithNavController(navController) appBarConfiguration = AppBarConfiguration(navController.graph, drawerLayout) toolbar.setupWithNavController(navController, appBarConfiguration) }
Call this function in onCreate. This creates the link between your drawer layout and nav graph, gives it a controller, and also gives the toolbar the drawer icon.
This code also ties everything together with the navigation so now, clicking on the navigation menu items will lead you to the corresponding fragment, provided you matched the names in the navigation and menu xml files.
override fun onSupportNavigateUp(): Boolean { val navController = findNavController(R.id.nav_host_fragment) return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp() }
Override this function too. Otherwise clicking the drawer icon will do nothing.
And just like that, you have a fully functioning navigation drawer.
Some common problems
Drawer Layout with a custom toolbar
<?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" android:id="@+id/drawerLayout" android:layout_width="match_parent" android:layout_height="match_parent"> <androidx.coordinatorlayout.widget.CoordinatorLayout android:layout_width="match_parent" android:layout_height="match_parent"> <com.google.android.material.appbar.AppBarLayout android:id="@+id/appBarLayout" android:layout_width="match_parent" android:layout_height="wrap_content"> <androidx.appcompat.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="@drawable/toolbar_bg"> <TextView style="@style/ToolbarText" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/app_name" /> </androidx.appcompat.widget.Toolbar> </com.google.android.material.appbar.AppBarLayout> <androidx.fragment.app.FragmentContainerView android:id="@+id/nav_host_fragment" android:name="androidx.navigation.fragment.NavHostFragment" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/main_bg" app:layout_behavior="@string/appbar_scrolling_view_behavior" app:defaultNavHost="true" app:navGraph="@navigation/nav_graph" /> </androidx.coordinatorlayout.widget.CoordinatorLayout> <com.google.android.material.navigation.NavigationView android:id="@+id/navView" android:layout_width="wrap_content" android:layout_height="match_parent" android:background="@drawable/main_bg" android:layout_gravity="start" android:fitsSystemWindows="true" app:headerLayout="@layout/nav_header_main" app:menu="@menu/menu_navigation" /> </androidx.drawerlayout.widget.DrawerLayout>
Here’s an example. I think you can figure out the rest.
Drawer icon is dark
<style name="Theme.MyAppTheme" parent="Theme.AppCompat.NoActionBar">
Set your app theme parent accordingly.