The side menu (or Navigation Drawer) is a key element of the interface of most modern Android applications. It allows users to quickly navigate between sections without cluttering the main screen. If you are just starting to develop applications in Android Studiocreating such a menu may seem like a daunting task. However, with the right approach and step-by-step guide, the process becomes clear even for beginners.
In this article we will look at how to add a side menu to your application, customize its appearance and functionality, and avoid common mistakes. You will learn which components Material Design to use, how to integrate menus with Fragment i Activity, and what tools Android Studio will simplify your work. It doesnโt matter whether you are creating a simple application or a complex project - Navigation Drawer will become an integral part of your UI.
What is a Navigation Drawer and why do you need it?
Side menu (Navigation Drawer) is a panel that slides out from the left (less often right) edge screen by swiping or clicking on the โhamburgerโ icon (โฐ). It has become the standard Material Design for applications with multiple partitions, such as Gmail, Google Drive or YouTube. Main advantages:
- ๐ฑ Saving screen space โthe main content is not overloaded with navigation buttons.
- ๐ Ease of switching โthe user can quickly go to any section of the application.
- ๐จ Design flexibility โsupports icons, headers, submenus and even animations.
- ๐ง Standardization โusers are already accustomed to this type of navigation, which reduces the barrier to entry.
From a technical point of view, Navigation Drawer is implemented through a combination of several components:
DrawerLayoutโ a container that controls the sliding of the menu.NavigationViewโ a widget for displaying menu items.ToolbarorAppBarโ a toolbar with a menu icon.Menuโ an XML file with a description of the menu items.
Without a side menu, applications with a large number of sections risk losing convenience. For example, imagine without the ability to quickly switch between โGames,โ โApplications,โ and โLibrary.โ This is why Google Play Market without the ability to quickly switch between โGamesโ, โApplicationsโ and โLibraryโ. That's why Navigation Drawer so popular among developers.
Preparing a project in Android Studio
Before adding a side menu, make sure your project is configured correctly. Here are the minimum requirements:
- ๐ Android Studio version 2022.2.1 or later (to support the latest libraries).
- ๐ฑ Minimum SDK version not lower
API 21 (Android 5.0 Lollipop). - ๐ง B file
build.gradle (Module: app)libraries must be included Material Components:
dependencies {implementation 'com.google.android.material:material:1.9.0'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
}
If you are creating a project from scratch, select a template Empty Activity โthis will simplify further configuration. If the project already exists, check that it is using Theme.MaterialComponents in the file themes.xml:
<style name="Theme.MyApplication" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
Also make sure that AndroidManifest.xml is set to the correct theme for Application:
<applicationandroid:theme="@style/Theme.MyApplication"
...>
If you are updating an old project, use Migration to AndroidX in the menu Refactor Android Studio to avoid library conflicts.
Creating a layout with Navigation Drawer
Now let's move on to practice. The main layout file is activity_main.xml. Open it and replace the content with the following code:
<?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"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:elevation="4dp"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"/>
<FrameLayout
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
<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"
app:headerLayout="@layout/nav_header"
app:menu="@menu/nav_menu"/>
</androidx.drawerlayout.widget.DrawerLayout>
Pay attention to the key elements:
DrawerLayoutโ the root container that controls the slide-out of the menu.Toolbarโ the toolbar, on which the menu icon will be displayed.FrameLayoutโ a container for dynamically loading fragments.NavigationViewโthe side menu itself with links tonav_header(header) andnav_menu(menu items).
Now create two new ones file:
res/layout/nav_header.xmlโ menu title layout (for example, with a user avatar).res/menu/nav_menu.xmlโ XML file with menu items.
Add DrawerLayout to activity_main.xml|
Create Toolbar for menu icon|
Add FrameLayout for fragments|
Create NavigationView with links to nav_header and nav_menu|
Check library connection Material Components-->
Setting menu items and header
File nav_menu.xml defines which items will be displayed in the side menu. An example of a simple menu with three sections:
<?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/nav_home"
android:icon="@drawable/ic_home"
android:title="Home"/>
<item
android:id="@+id/nav_gallery"
android:icon="@drawable/ic_gallery"
android:title="Gallery"/>
<item
android:id="@+id/nav_slideshow"
android:icon="@drawable/ic_slideshow"
android:title="Slideshow"/>
</group>
<menu>
<item
android:id="@+id/nav_share"
android:icon="@drawable/ic_share"
android:title="Share"/>
<item
android:id="@+id/nav_send"
android:icon="@drawable/ic_send"
android:title="Send feedback"/>
</menu>
</item>
</menu>
Key attributes:
android:checkableBehavior="single"โ allows you to highlight the currently selected item.android:iconโ icon for menu item (must be in the folderres/drawable).android:titleโthe text that will be displayed.
For the menu title (nav_header.xml) you can use the following template:
<?xml version="1.0" encoding="utf-8"?><LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="180dp"
android:background="?attr/colorPrimary"
android:gravity="bottom"
android:orientation="vertical"
android:padding="16dp"
android:theme="@style/ThemeOverlay.AppCompat.Dark">
<ImageView
android:id="@+id/imageView"
android:layout_width="60dp"
android:layout_height="60dp"
android:src="@drawable/ic_profile"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Username"
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
android:textColor="@android:color/white"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="user@example.com"
android:textAppearance="@style/TextAppearance.AppCompat.Body2"
android:textColor="@android:color/white"/>
</LinearLayout>
Important: height header (android:layout_height) is better to set fixed (for example, 180dp) to avoid problems with display on different devices.
Where can I get icons for the menu?
Icons for Navigation Drawer can be downloaded from official website Material Design Icons (https://material.io/resources/icons/) or use built-in Android Studio via Vector Asset Studio (RMB by folder res/drawable โ New โ Vector Asset).
Integration with MainActivity
Now Let's connect the layout with the application logic. Open the file MainActivity.kt (or MainActivity.java) and add the following code:
class MainActivity : AppCompatActivity() {private lateinit var drawerLayout: DrawerLayout
private lateinit var navView: NavigationView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Initializing Toolbar
val toolbar: Toolbar = findViewById(R.id.toolbar)
setSupportActionBar(toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
// Initializing DrawerLayout and NavigationView
drawerLayout = findViewById(R.id.drawer_layout)
navView = findViewById(R.id.nav_view)
// Setting the menu icon
toolbar.setNavigationIcon(R.drawable.ic_menu)
toolbar.setNavigationOnClickListener {
drawerLayout.openDrawer(GravityCompat.START)
}
// Processing clicks on menu items
navView.setNavigationItemSelectedListener { menuItem ->
when (menuItem.itemId) {
R.id.nav_home -> {
supportFragmentManager.beginTransaction()
.replace(R.id.fragment_container, HomeFragment())
.commit()
menuItem.isChecked = true
}
R.id.nav_gallery -> {
supportFragmentManager.beginTransaction()
.replace(R.id.fragment_container, GalleryFragment())
.commit()
menuItem.isChecked = true
}
R.id.nav_slideshow -> {
supportFragmentManager.beginTransaction()
.replace(R.id.fragment_container, SlideshowFragment())
.commit()
menuItem.isChecked = true
}
}
drawerLayout.closeDrawer(GravityCompat.START)
true
}
}
// Processing clicks on the "Back" button
override fun onBackPressed() {
if (drawerLayout.isDrawerOpen(GravityCompat.START)) {
drawerLayout.closeDrawer(GravityCompat.START)
} else {
super.onBackPressed()
}
}
}
In this code:
- ๐ง It is initialized
Toolbarand set asActionBar. - ๐ The menu icon (
ic_menu) and the handler for its click are configured. - ๐ The logic of switching between fragments when selecting menu items is implemented.
- ๐ Adds processing for the "Back" button to close the menu.
Don't forget to create fragment classes (HomeFragment, GalleryFragment, SlideshowFragment) or replace them with your own. Example of a simple fragment:
class HomeFragment : Fragment() {override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_home, container, false)
}
}
Always check that DrawerLayout closes when clicking on a menu item (drawerLayout.closeDrawer()), otherwise the user will remain with an open menu after selecting a section.
Adding animations and customization
Standard Navigation Drawer can be improved with animations and styles. For example, to make the menu slide out smoothly, add the following style to styles.xml following style:
<style name="DrawerArrowStyle" parent="@style/Widget.AppCompat.DrawerArrowToggle"><item name="spinBars">true</item>
<item name="color">@android:color/white</item>
</style>
Then apply it to the menu icon in MainActivity:
val toggle = ActionBarDrawerToggle(this, drawerLayout, toolbar,
R.string.navigation_drawer_open,
R.string.navigation_drawer_close
)
drawerLayout.addDrawerListener(toggle)
toggle.syncState()
To customize the appearance NavigationView use attributes in activity_main.xml:
<com.google.android.material.navigation.NavigationView...
app:itemIconTint="@color/nav_menu_icon_color"
app:itemTextColor="@color/nav_menu_text_color"
app:itemBackground="@drawable/nav_menu_item_background"/>
Where:
nav_menu_icon_colorโ icon color (for example,@color/black).nav_menu_text_colorโ text color.nav_menu_item_backgroundโ menu item background when hovering (you can useselector).
Example file res/drawable/nav_menu_item_background.xml to change the background when when pressed:
<?xml version="1.0" encoding="utf-8"?><selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@color/colorPrimaryLight" android:state_pressed="true"/>
<item android:drawable="@android:color/transparent"/>
</selector>
To make the menu open smoothly, add android:windowAnimationStyle to the theme of an application with custom animation.
Typical mistakes and how to avoid them
When working with Navigation Drawer developers often encounter the following problems:
| Problem | Cause | Solution |
|---|---|---|
| Menu does not open by swipe | Not specified android:layout_gravity="start" for NavigationView |
Add an attribute to the layout or check that DrawerLayout is the root element |
| Menu icon is not displayed | Not called setSupportActionBar(toolbar) or not set setNavigationIcon() |
Check initialization Toolbar and the presence of an icon in res/drawable |
| The application crashes when you click on a menu item | Not implemented setNavigationItemSelectedListener or an error in Fragment |
Add an event handler and check the correctness of transactions with fragments |
| The menu opens on top of the keyboard | DrawerLayout does not take into account android:fitsSystemWindows |
Add android:fitsSystemWindows="true" to the root DrawerLayout |
| Menu items are not highlighted when selected | Not specified android:checkableBehavior="single" in nav_menu.xml |
Add an attribute to the group of menu items |
Another common mistake is memory leak when opening/closing the menu frequently. To avoid this, always close DrawerLayout after selecting an item:
drawerLayout.closeDrawer(GravityCompat.START)
Also make sure that fragments are not duplicated when you repeatedly click on the same menu item. To do this, add a check:
if (menuItem.itemId != navView.menu.findItem(R.id.nav_home).itemId) {// Loading a new fragment
}
How to debug problems with Navigation Drawer?
Use Logcat in Android Studio to find errors. Filter logs by tag "DrawerLayout" or "NavigationView". If the menu does not respond to swipes, check if another element is blocking it (for example, RecyclerView with horizontal scrolling).
Optimization for different screens
The side menu should display correctly on devices with different screen sizes - from smartphones to tablets. Here are some adaptation tips:
- ๐ฑ For smartphones: use the standard menu width (
wrap_contentor a fixed value, for example320dp). - ๐ฅ๏ธ For tablets: you can increase the menu width to
400dpor make it always open (modelocked open). - ๐ For folding devices: check the behavior of the menu when changing the screen orientation.
To have the menu automatically adjust to the screen size, add to values i values-sw600dp different styles. For example, for tablets (res/values-sw600dp/styles.xml):
<style name="NavigationViewStyle" parent="@style/Widget.Design.NavigationView"><item name="android:layout_width">400dp</item>
</style>
To support dark theme add alternative colors to res/values-night/colors.xml:
<color name="nav_menu_background">#212121</color>
<color name="nav_menu_text_color">#FFFFFF</color>
And apply them in the layout:
app:itemTextColor="@color/nav_menu_text_color"app:itemIconTint="@color/nav_menu_text_color"
app:backgroundTint="@color/nav_menu_background"
Always test the side menu on devices with different screen sizes. Use Android Studio Emulator with profiles Pixel 5 (smartphone) and Pixel C (tablet).
FAQ: Frequently asked questions about Navigation Drawer
How to make the menu open on the right?
Change android:layout_gravity="start" to android:layout_gravity="end" to NavigationViewAlso update the menu opening handler:
drawerLayout.openDrawer(GravityCompat.END)
Is it possible to add dynamic ones to the menu? items?
Yes, use NavigationView.getMenu().add() in runtime. Example:
navView.menu.add("Dynamic item").setIcon(R.drawable.ic_dynamic)
Don't forget to update the handler clicks.
How to change the color of the status bar when the menu is open?
Add to styles.xml:
<item name="android:statusBarColor">@android:color/transparent</item>
And set the flag View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR to MainActivity:
window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
Why does the menu open on top of the keyboard?
Add to AndroidManifest.xml for Activity:
android:windowSoftInputMode="adjustResize|adjustPan"
Or programmatically hide the keyboard before opening the menu:
val imm = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(currentFocus?.windowToken, 0)
How to add animation when opening a menu?
Create an animation file res/anim/slide_in.xml:
<set xmlns:android="http://schemas.android.com/apk/res/android"><translate
android:duration="300"
android:fromXDelta="-100%"
android:toXDelta="0%" />
</set>
And apply it to DrawerLayout:
drawerLayout.setScrimColor(Color.TRANSPARENT)drawerLayout.addDrawerListener(object : DrawerLayout.DrawerListener {
override fun onDrawerSlide(drawerView: View, slideOffset: Float) {
drawerView.translationX = slideOffset * drawerView.width
}
// Leave other methods empty
})