Recently I was struggling with Navigation Component and succeded in solving some of its issues. I am happy to share with you the solutions I’ve found.
GitHub Repo: https://github.com/Pulimet/NavigationComponentSample
Create a project and select the template “Navigation Drawer Activity”. You will get the ToolBar, Drawer and navigation stuff for free as shown in the screenshot.
Now, let’s assume that we got a request to move the drawer under the ToolBar. We need to modify activity_main.xml for that.
Create vertical LinearLayout and make it wrapping DrawerLayout
Open app_bar_main.xml copy AppBarLayout and paste it as a first item in the previously created LinearLayout.
Also from the app_bar_main.xml get the include (content_main) and put it as a first child of DrawerLayout instead of existing include of app_bar_main.xml.
Delete app_bar_main.xml file
In v21\styles.xml – remove the line that makes status bar transparent.
Before editing (activity_main.xml):
<? 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/drawerLayout" 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/navView" 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 > |
The result (activity_main.xml):
<? xml version = "1.0" encoding = "utf-8" ?> < LinearLayout 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" android:fitsSystemWindows = "true" android:orientation = "vertical" > < com.google.android.material.appbar.AppBarLayout android:layout_height = "wrap_content" android:layout_width = "match_parent" 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 > < androidx.drawerlayout.widget.DrawerLayout android:id = "@+id/drawerLayout" android:layout_width = "match_parent" android:layout_height = "match_parent" android:fitsSystemWindows = "true" tools:openDrawer = "start" > < include layout = "@layout/content_main" /> < 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:headerLayout = "@layout/nav_header_main" app:menu = "@menu/activity_main_drawer" /> </ androidx.drawerlayout.widget.DrawerLayout > </ LinearLayout > |
Looks awesome, but we are missing the animation for the hamburger menu icon, while Drawer opens or closes.
To fix this we will add a DrawerListener. (The code is below, setDrawerListener())
But now, when the drawer is open and we click on the arrow, nothing is happing.
To fix this we need to handle the icon click event. (The code is below, fixNavigationIconBehavior())
Remove onSupportNavigateUp() method, since we will be doing it’s work instead:)
One last thing, we need to handle the back click by closing the drawer first. And just when the drawer closed, the back button should close the app.(onBackPressed())
override fun onCreate(savedInstanceState: Bundle?) { super .onCreate(savedInstanceState) setContentView(R.layout.activity_main) setToolBarAndNavigation() } private fun setToolBarAndNavigation() { setSupportActionBar(toolbar) navController = findNavController(R.id.nav_host_fragment) // Passing each menu ID as a set of Ids because each // menu should be considered as top level destinations. appBarConfiguration = AppBarConfiguration( setOf( R.id.nav_home, R.id.nav_gallery, R.id.nav_slideshow, R.id.nav_tools, R.id.nav_share, R.id.nav_send ), drawerLayout ) setupActionBarWithNavController(navController, appBarConfiguration) navView.setupWithNavController(navController) menuDrawer = toolbar.navigationIcon as DrawerArrowDrawable setDrawerListener() fixNavigationIconBehavior() } private fun setDrawerListener() { drawerLayout.addDrawerListener(object : DrawerLayout.SimpleDrawerListener() { override fun onDrawerSlide(drawerView: View, slideOffset: Float) { menuDrawer.progress = slideOffset } }) } private fun isMenuDrawerIsAnArrowNow() = menuDrawer.progress == 1.0f private fun fixNavigationIconBehavior() { toolbar.setNavigationOnClickListener { if (drawerLayout.isDrawerOpen(GravityCompat.START)) { drawerLayout.closeDrawer(GravityCompat.START) } else { if (isMenuDrawerIsAnArrowNow()) { navController.navigateUp() } else { drawerLayout.openDrawer(GravityCompat.START) } } } } override fun onBackPressed() { when { drawerLayout.isDrawerOpen(GravityCompat.START) -> drawerLayout.closeDrawer(GravityCompat.START) else -> super .onBackPressed() } } |