Navigation Drawer (Side Menu)
Navigation drawer क्या है?
Navigation drawer वह side menu है जो ☰ tap करने या किनारे से swipe करने पर बाईं ओर से आता है। इसमें header (user photo और नाम) और destinations की list होती है।
Building blocks
Step 1: activity_main.xml
<?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>Step 2: Drawer header
<?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>Step 3: Drawer menu
<group android:checkableBehavior="single"> current screen highlight करता है। Title वाला sub-menu "More" section बनाता है। Destination items nav graph ids reuse करते हैं; action_share एक normal action है।
<?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
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)))
}
}Drawer click कैसे काम करता है
Back button से drawer बंद
MainActivity का OnBackPressedCallback isDrawerOpen(GravityCompat.START) check करता है: drawer खुला हो तो Back उसे बंद करता है; नहीं तो callback कुछ पल के लिए खुद को disable करके NavHost को पीछे जाने देता है।
आम गलतियाँ
- DrawerLayout में NavigationView पहले रखना → content ढक जाता है और बंद नहीं होता।
- NavigationView पर
android:layout_gravity="start"नहीं → crash "No drawer view found"। - ActionBar वाली theme और आपका Toolbar → दो bars; NoActionBar theme use करें।
onNavDestinationSelectedcall किए बिनाsetNavigationItemSelectedListener→ menu clicks navigate करना बंद।
सारांश
- DrawerLayout(content, NavigationView) + header layout + menu XML।
AppBarConfiguration(topLevelIds, drawerLayout)☰ icon देता है;navView.setupWithNavControlleritems जोड़ता है।- Extra items खुद handle करें, drawer बंद करें, और Back पर बंद करें।
Drawer में "Rate us" item जोड़िए जो implicit intent से Play Store page खोले, और header में नाम के नीचे user का email दिखाइए।
