Free tutorials & notes in Hindi & English · Clean code examples 🧰 Free PDF & Image Tools →
📋 Screens, Lists & Navigation  ·  Lesson 27

Navigation Drawer (Side Menu)

What is a navigation drawer?

A navigation drawer is the side menu that slides in from the left when you tap ☰ or swipe from the edge. It shows a header (user photo and name) and a list of destinations.

9:41▮▮ 85%☰Student Diary⋮Maths homeworkHighPhysics notesChapter 4📝Notes📚Subjects📊Progress9:41▮▮ 85%Student Diary⋮👤Hello, Riya 👋🏠Notes📦Favourites♡Subjects⚙️Progress❓Settings🚪Help & Tutorial📝Share app
Closed and open — the drawer of the final app

The building blocks

DrawerLayoutroot – 1st child = content, 2nd child = drawerCoordinatorLayout (content)Toolbar + NavHost + BottomNav + FABNavigationView (drawer, layout_gravity="start")headerLayout + menu
Order matters: the drawer is the LAST child

Step 1: activity_main.xml

XML – res/layout/activity_main.xml (Student Diary)
<?xml version="1.0" encoding="utf-8"?>
<!-- DrawerLayout = the side menu slides over the main content -->
<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">

    <!-- 1st child: main content -->
    <androidx.coordinatorlayout.widget.CoordinatorLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <com.google.android.material.appbar.AppBarLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <com.google.android.material.appbar.MaterialToolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize" />
        </com.google.android.material.appbar.AppBarLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical"
            app:layout_behavior="@string/appbar_scrolling_view_behavior">

            <!-- Screens (fragments) are swapped here by the Navigation Component -->
            <androidx.fragment.app.FragmentContainerView
                android:id="@+id/nav_host"
                android:name="androidx.navigation.fragment.NavHostFragment"
                android:layout_width="match_parent"
                android:layout_height="0dp"
                android:layout_weight="1"
                app:defaultNavHost="true"
                app:navGraph="@navigation/nav_graph" />

            <com.google.android.material.bottomnavigation.BottomNavigationView
                android:id="@+id/bottomNav"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                app:menu="@menu/bottom_nav_menu" />
        </LinearLayout>

        <com.google.android.material.floatingactionbutton.FloatingActionButton
            android:id="@+id/fab"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom|end"
            android:layout_marginEnd="16dp"
            android:layout_marginBottom="96dp"
            android:contentDescription="@string/add_note"
            app:srcCompat="@drawable/ic_add" />
    </androidx.coordinatorlayout.widget.CoordinatorLayout>

    <!-- 2nd child: the drawer itself -->
    <com.google.android.material.navigation.NavigationView
        android:id="@+id/navView"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        app:headerLayout="@layout/nav_header"
        app:menu="@menu/drawer_menu" />
</androidx.drawerlayout.widget.DrawerLayout>
XML – res/layout/nav_header.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"
    android:layout_width="match_parent"
    android:layout_height="176dp"
    android:background="@color/brand"
    android:gravity="bottom"
    android:orientation="vertical"
    android:padding="16dp">

    <ImageView
        android:layout_width="64dp"
        android:layout_height="64dp"
        android:background="@drawable/bg_circle_white"
        android:contentDescription="@string/app_name"
        android:padding="12dp"
        android:src="@drawable/ic_note"
        app:tint="@color/brand" />

    <TextView
        android:id="@+id/tvUserName"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="12dp"
        android:text="@string/app_name"
        android:textAppearance="?attr/textAppearanceTitleMedium"
        android:textColor="@android:color/white" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/tagline"
        android:textColor="#E0FFFFFF" />
</LinearLayout>

A <group android:checkableBehavior="single"> highlights the current screen. A sub-menu with a title creates the "More" section. Destination items reuse nav graph ids; action_share is a normal action.

XML – res/menu/drawer_menu.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <group android:checkableBehavior="single">
        <item android:id="@+id/notesFragment" android:icon="@drawable/ic_note" android:title="@string/menu_notes" />
        <item android:id="@+id/favoritesFragment" android:icon="@drawable/ic_star" android:title="@string/menu_favourites" />
        <item android:id="@+id/subjectsFragment" android:icon="@drawable/ic_subject" android:title="@string/menu_subjects" />
        <item android:id="@+id/statsFragment" android:icon="@drawable/ic_stats" android:title="@string/menu_stats" />
    </group>
    <item android:title="@string/menu_more">
        <menu>
            <item android:id="@+id/settingsFragment" android:icon="@drawable/ic_settings" android:title="@string/menu_settings" />
            <item android:id="@+id/helpFragment" android:icon="@drawable/ic_help" android:title="@string/menu_help" />
            <item android:id="@+id/action_share" android:icon="@drawable/ic_share" android:title="@string/share_app" />
        </menu>
    </item>
</menu>

Step 4: MainActivity

Kotlin – MainActivity.kt (complete)
package com.codingeasily.studentdiary

import android.Manifest
import android.content.Intent
import android.os.Build
import android.os.Bundle
import androidx.activity.OnBackPressedCallback
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.GravityCompat
import androidx.core.view.isVisible
import androidx.navigation.NavController
import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.NavigationUI
import androidx.navigation.ui.navigateUp
import androidx.navigation.ui.setupActionBarWithNavController
import androidx.navigation.ui.setupWithNavController
import com.codingeasily.studentdiary.data.SettingsStore
import com.codingeasily.studentdiary.databinding.ActivityMainBinding
import com.codingeasily.studentdiary.databinding.NavHeaderBinding
import com.codingeasily.studentdiary.reminder.NotificationHelper
import com.google.android.material.snackbar.Snackbar

/**
 * The only Activity. It hosts: Toolbar + Navigation Drawer + Bottom Navigation + FAB
 * and a NavHostFragment that swaps the screens (fragments).
 */
class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding
    private lateinit var navController: NavController
    private lateinit var appBarConfiguration: AppBarConfiguration

    // Android 13+: ask for notification permission (result comes back here)
    private val notificationPermission =
        registerForActivityResult(ActivityResultContracts.RequestPermission()) { granted ->
            if (!granted) {
                Snackbar.make(binding.root, R.string.notifications_off, Snackbar.LENGTH_LONG).show()
            }
        }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        setSupportActionBar(binding.toolbar)

        val navHost = supportFragmentManager.findFragmentById(R.id.nav_host) as NavHostFragment
        navController = navHost.navController

        // Top-level screens show the ☰ (drawer) icon; other screens show ←
        val topLevel = setOf(
            R.id.notesFragment, R.id.subjectsFragment, R.id.statsFragment,
            R.id.favoritesFragment, R.id.settingsFragment, R.id.helpFragment
        )
        appBarConfiguration = AppBarConfiguration(topLevel, binding.drawerLayout)
        setupActionBarWithNavController(navController, appBarConfiguration)
        binding.bottomNav.setupWithNavController(navController)
        binding.navView.setupWithNavController(navController)

        // Drawer has one extra item ("Share app") that is not a screen
        binding.navView.setNavigationItemSelectedListener { item ->
            if (item.itemId == R.id.action_share) shareApp()
            else NavigationUI.onNavDestinationSelected(item, navController)
            binding.drawerLayout.closeDrawer(GravityCompat.START)
            true
        }

        // Show bottom bar only on the 3 main tabs, FAB only on the notes list
        val bottomScreens = setOf(R.id.notesFragment, R.id.subjectsFragment, R.id.statsFragment)
        navController.addOnDestinationChangedListener { _, destination, _ ->
            binding.bottomNav.isVisible = destination.id in bottomScreens
            if (destination.id == R.id.notesFragment) binding.fab.show() else binding.fab.hide()
        }
        binding.fab.setOnClickListener { navController.navigate(R.id.action_global_editor) }

        // Close the drawer with the back button before leaving the screen
        onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
            override fun handleOnBackPressed() {
                if (binding.drawerLayout.isDrawerOpen(GravityCompat.START)) {
                    binding.drawerLayout.closeDrawer(GravityCompat.START)
                } else {
                    isEnabled = false
                    onBackPressedDispatcher.onBackPressed()
                    isEnabled = true
                }
            }
        })

        askNotificationPermission()
    }

    override fun onResume() {
        super.onResume()
        // The name can change in Settings, so refresh the drawer header every time
        val header = NavHeaderBinding.bind(binding.navView.getHeaderView(0))
        header.tvUserName.text = getString(R.string.hello_user, SettingsStore(this).userName)
    }

    override fun onSupportNavigateUp(): Boolean =
        navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()

    private fun askNotificationPermission() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU && !NotificationHelper.canNotify(this)) {
            notificationPermission.launch(Manifest.permission.POST_NOTIFICATIONS)
        }
    }

    private fun shareApp() {
        val send = Intent(Intent.ACTION_SEND).apply {
            type = "text/plain"
            putExtra(Intent.EXTRA_TEXT, getString(R.string.share_text))
        }
        startActivity(Intent.createChooser(send, getString(R.string.share_app)))
    }
}

How a drawer click works

UserNavigationViewMainActivityNavControllertap "Favourites"item selected listeneronNavDestinationSelected(item)show favoritesFragmentcloseDrawer(START)destination changed → item checked
Share app is handled separately (not a destination)

Back button closes the drawer

The OnBackPressedCallback in MainActivity checks isDrawerOpen(GravityCompat.START): if the drawer is open, Back closes it; otherwise the callback disables itself for a moment and lets the NavHost go back.

Common mistakes

  • NavigationView placed first inside DrawerLayout → it covers the content and cannot close.
  • Missing android:layout_gravity="start" on NavigationView → crash "No drawer view found".
  • Theme with an ActionBar plus your Toolbar → two bars; use a NoActionBar theme.
  • Calling setNavigationItemSelectedListener without calling onNavDestinationSelected → menu clicks stop navigating.

Summary

  • DrawerLayout(content, NavigationView) + header layout + menu XML.
  • AppBarConfiguration(topLevelIds, drawerLayout) gives the ☰ icon; navView.setupWithNavController links items.
  • Handle extra items yourself, close the drawer, and close it on Back.
✅ Practice

Add a "Rate us" item to the drawer that opens the Play Store page with an implicit intent, and show the user's email under the name in the header.

Frequently Asked Questions

Drawer or bottom navigation?
Bottom navigation is for 3–5 screens used constantly. A drawer holds more destinations and less frequent items such as Settings, Help and Share. Student Diary uses both.
Why does the hamburger icon not appear?
Pass the DrawerLayout to AppBarConfiguration and call setupActionBarWithNavController. The current destination must be one of the top-level ids.
How do I change the header text from code?
Get the header with navView.getHeaderView(0), bind it with NavHeaderBinding.bind(...) and set the TextView text.
← Android Tutorial (Kotlin)
🔗

Share this topic with a friend

यह topic किसी दोस्त को भेजें

Found it useful? Send it to a classmate learning the same thing.

अच्छा लगा? जो दोस्त यही सीख रहा है, उसे भेज दीजिए।

Next topicTabLayout & ViewPager2 Your progress: 27 / 43 (63%) · Lesson 28 / 43 Continue →

How was this lesson?

Your feedback helps us make the content better.

Write a review or suggestion (optional)

After approval, your name and city may appear publicly with your review. Please do not write your email or phone number.

▶ CodingEasily on YouTube

Learn with video lessons in easy Hindi

Featured video: RDBMS Part 3 – Class XI Commerce IT

▶ Subscribe – it’s free