Navigation drawers provide access to destinations in your app.
Contents
- Using navigation drawers
- Anatomy
- Standard navigation drawers
- Modal navigation drawers
- Bottom navigation drawers
- Theming
Before you can use navigation drawers, you need to add a dependency to the
Material Components for Android library. For more information, go to the
getting started
page. For modal navigation drawers you also need to add a dependency to tne
AndroidX DrawerLayout
library. For more information go to the
releases
page.
The content of all navigation drawer types can be implemented using a
NavigationView
.
<com.google.android.material.navigation.NavigationView
android:id="@+id/navigationView"
... />
Note: The layout_width
and layout_height
attributes should be set to
wrap_content
, match_parent
, or a custom dimension depending on the
navigation drawer type and parent ViewGroup
.
In the layout:
<com.google.android.material.navigation.NavigationView
...
app:menu="@menu/navigation_drawer" />
In res/menu/navigation_drawer.xml
:
<menu ...>
<group
android:id="@+id/group1"
android:checkableBehavior="single">
<item
android:id="@+id/item1"
android:icon="@drawable/ic_favorite_24dp"
android:title="@string/title_1"
android:checked="true" />
<item
android:id="@+id/item2"
android:icon="@drawable/ic_favorite_24dp"
android:title="@string/title_2" />
<item
android:id="@+id/item3"
android:icon="@drawable/ic_favorite_24dp"
android:title="@string/title_3" />
</group>
</menu>
In the layout:
<com.google.android.material.navigation.NavigationView
...
app:headerLayout="@layout/header_navigation_drawer" />
In res/layout/header_navigation_drawer.xml
:
<LinearLayout
...
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:layout_marginStart="24dp"
android:layout_marginEnd="24dp"
android:textAppearance="?attr/textAppearanceHeadline6"
android:text="@string/header_title" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="24dp"
android:layout_marginStart="24dp"
android:layout_marginEnd="24dp"
android:textAppearance="?attr/textAppearanceBody2"
android:textColor="@color/material_on_surface_emphasis_medium"
android:text="@string/header_text" />
</LinearLayout>
Dividers are automatically added between <group>
s with unique IDs. When a
sub-<menu>
is added to an item it is treated as a subtitle.
In res/menu/navigation_drawer.xml
:
<menu ...>
<group
android:id="@+id/group1"
...>
...
</group>
<group
android:id="@+id/group2"
android:checkableBehavior="single">
<item
android:id="@+id/subtitle"
android:title="Subtitle">
<menu>
<item
android:id="@+id/item4"
android:icon="@drawable/ic_favorite_24dp"
android:title="Item 4" />
<item
android:id="@+id/item5"
android:icon="@drawable/ic_favorite_24dp"
android:title="Item 5" />
</menu>
</item>
</group>
</menu>
Navigation drawers support content labeling for accessibility and are readable by most screen readers, such as TalkBack. Text rendered in menu items is automatically provided to accessibility services. Additional content labels are optional but recommended.
For more information on content labels, go to the Android accessibility help guide.
A content description can be set on <item>
s in the NavigationView
menu so
that screen readers like TalkBack are able to announce their purpose or action,
if any. This can be done in XML using the android:contentDescription
attribute
or programmatically with
navigationView.menu.findItem(R.id.itemId)#setContentDescription
(on API 26 and
above).
Any ImageView
s within the header layout should also have a content description
set on them.
To open navigation drawers, use clickable widgets that meet the minimum touch
target size of 48dp
and are properly labeled for accessibility. To close
navigation drawers, consider doing the same but bear in mind that clicking on
menu items or an optional scrim should also serve this purpose.
Navigation drawers can be used with the AndroidX Navigation library. For more information, go to the documentation.
Navigation drawers have a container, an optional header, optional dividers, items with inactive text, active text, and an active text overlay, optional subtitles, and an optional scrim.
- Container
- Header (optional)
- Divider (optional)
- Active text overlay
- Active text
- Inactive text
- Subtitle (optional)
- Scrim (optional)
Element | Attribute(s) | Related method(s) | Default value |
---|---|---|---|
Color | android:background |
setBackground getBackground |
?attr/colorSurface |
Shape | app:shapeAppearance app:shapeAppearanceOverlay |
N/A | null |
Elevation | app:elevation (can be used on NavigationView or DrawerLayout ) |
setElevation getElevation |
16dp (NavigationView ) or 10dp (DrawerLayout ) |
Max width | android:maxWidth |
N/A | 280dp |
Fits system windows | android:fitsSystemWindows |
setFitsSystemWindows getFitsSystemWindows |
true |
Element | Attribute | Related method(s) | Default value |
---|---|---|---|
Layout | app:headerLayout |
addHeaderView inflateHeaderView getHeaderView getHeaderCount removeHeaderView |
null |
Element | Attribute | Related method(s) | Default value |
---|---|---|---|
Divider | android:listDivider in app theme |
N/A | Varies per platform version |
Height | N/A (see layout) | N/A | 1dp |
Element | Attribute(s) | Related method(s) | Default value |
---|---|---|---|
Color | app:itemShapeFillColor |
N/A | ?attr/colorPrimary at 12% opacity (see all states) |
Shape | app:itemShapeAppearance app:itemShapeAppearanceOverlay |
N/A | ?attr/shapeAppearanceSmallComponent null |
Insets | app:itemShapeInsetStart app:itemShapeInsetTop app:itemShapeInsetEnd app:itemShapeInsetBottom |
N/A | 8dp 4dp 8dp 4dp |
Horizontal padding | app:itemHorizontalPadding |
setItemHorizontalPadding setItemHorizontalPaddingResource getItemHorizontalPadding |
22dp |
Element | Attribute | Related method(s) | Default value |
---|---|---|---|
Color | app:itemTextColor |
setItemTextColor getItemTextColor |
?attr/colorPrimary when active else ?attr/colorOnSurface (see all states) |
Typograhphy | app:itemTextAppearance |
setItemTextAppearance |
?attr/textAppearanceSubtitle2 |
Max lines | app:itemMaxLines |
setItemMaxLines getItemMaxLines |
1 |
Element | Attribute | Related method(s) | Default value |
---|---|---|---|
Color | app:itemIconTint |
setIconItemTintList getIconItemTintList |
?attr/colorPrimary when active else ?attr/colorOnSurface (see all states) |
Size | app:itemIconSize |
setItemIconSize |
24dp |
Padding | app:itemIconPadding |
setItemIconPadding setItemIconPaddingResource getItemIconPadding |
14dp |
Element | Attribute | Related method(s) | Default value |
---|---|---|---|
Color | N/A (see layout) | N/A | ?android:textColorSecondary |
Typography | N/A | N/A | @style/TextAppearance.AppCompat.Body2 |
Max lines | N/A | N/A | 1 |
Height | N/A | N/A | ?attr/listPreferredItemHeightSmall |
Padding | N/A | N/A | ?attr/listPreferredItemPaddingLeft and ?attr/listPreferredItemPaddingRight |
Element | Attribute | Related method(s) | Default value |
---|---|---|---|
Color | N/A | setScrimColor on DrawerLayout |
Black at 60% opacity |
Element | Style |
---|---|
Default style | Widget.MaterialComponents.NavigationView |
Default style theme attribute: ?attr/navigationViewStyle
Default style theme attribute: ?attr/drawerLayoutStyle
There are three types of navigation drawers: 1. Standard navigation drawer, 2. Modal navigation drawer, 3. Bottom navigation drawer
Standard navigation drawers allow interaction with both screen content and the drawer at the same time. They can be used on tablet and desktop, but they aren’t suitable for mobile due to limited screen size.
API and source code:
NavigationView
The following example shows a permanently visible standard navigation drawer.
In the layout:
<androidx.constraintlayout.widget.ConstraintLayout
...
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.navigation.NavigationView
...
android:layout_width="wrap_content"
android:layout_height="match_parent"
app:layout_constraintStart_toStartOf="parent" />
<!-- Screen content (constrained to end of navigationView) -->
</androidx.constraintlayout.widget.ConstraintLayout>
In res/values/themes.xml
:
<style name="Theme.App" parent="Theme.MaterialComponents.DayNight.*">
<item name="android:windowTranslucentStatus">true</item>
</style>
In res/layout/header_navigation_drawer.xml
:
<LinearLayout
...
android:fitsSystemWindows="true">
...
</LinearLayout>
Modal navigation drawers block interaction with the rest of an app’s content with a scrim. They are elevated above most of the app’s UI and don’t affect the screen’s layout grid.
They are primarily for use on mobile where screen space is limited, and can be replaced by standard drawers on tablet and desktop.
API and source code:
NavigationView
DrawerLayout
The following example shows a modal navigation drawer with a top app bar.
In the layout:
<androidx.drawerlayout.widget.DrawerLayout
...
android:id="@+id/drawerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:openDrawer="start">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/Widget.MaterialComponents.AppBarLayout.PrimarySurface"
android:fitsSystemWindows="true">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/topAppBar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:title="@string/top_app_bar"
app:navigationIcon="@drawable/ic_menu_24dp"
style="@style/Widget.MaterialComponents.Toolbar.PrimarySurface"
android:background="@android:color/transparent"
android:elevation="0dp" />
</com.google.android.material.appbar.AppBarLayout>
<!-- Screen content -->
<!-- Use app:layout_behavior="@string/appbar_scrolling_view_behavior" to fit below top app bar -->
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<com.google.android.material.navigation.NavigationView
...
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start" />
</androidx.drawerlayout.widget.DrawerLayout>
In res/values/themes.xml
:
<style name="Theme.App" parent="Theme.MaterialComponents.DayNight.*">
<item name="android:windowTranslucentStatus">true</item>
</style>
In res/layout/header_navigation_drawer.xml
:
<LinearLayout
...
android:fitsSystemWindows="true">
...
</LinearLayout>
In code:
topAppBar.setNavigationOnClickListener {
drawerLayout.open()
}
navigationView.setNavigationItemSelectedListener { menuItem ->
// Handle menu item selected
menuItem.isChecked = true
drawerLayout.close()
true
}
For more information on top app bars see the documentation.
Bottom navigation drawers are modal drawers that are anchored to the bottom of the screen instead of the left or right edge. They are only used with bottom app bars.
These drawers open upon tapping the navigation menu icon in the bottom app bar. They are only for use on mobile.
API and source code:
NavigationView
BottomSheetBehavior
The following example shows a bottom navigation drawer with a bottom app bar.
In the layout:
<androidx.coordinatorlayout.widget.CoordinatorLayout
...
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="?attr/actionBarSize">
<!-- Screen content -->
<FrameLayout
android:id="@+id/scrim"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.google.android.material.navigation.NavigationView
...
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="@string/bottom_sheet_behavior"
app:behavior_hideable="true" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<com.google.android.material.bottomappbar.BottomAppBar
android:id="@+id/bottomAppBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
style="@style/Widget.MaterialComponents.BottomAppBar.PrimarySurface"
app:navigationIcon="@drawable/ic_menu_24dp" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
In code:
val bottomSheetBehavior = BottomSheetBehavior.from(navigationView)
bottomSheetBehavior.state = BottomSheetBehavior.STATE_HIDDEN
bottomAppBar.setNavigationOnClickListener {
bottomSheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED
}
navigationView.setNavigationItemSelectedListener { menuItem ->
// Handle menu item selected
menuItem.isChecked = true
bottomSheetBehavior.state = BottomSheetBehavior.STATE_HIDDEN
true
}
scrim.setOnClickListener {
bottomSheetBehavior.state = BottomSheetBehavior.STATE_HIDDEN
}
bottomSheetBehavior.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
override fun onSlide(bottomSheet: View, slideOffset: Float) {
val baseColor = Color.BLACK
// 60% opacity
val baseAlpha = ResourcesCompat.getFloat(resources, R.dimen.material_emphasis_medium)
// Map slideOffset from [-1.0, 1.0] to [0.0, 1.0]
val offset = (slideOffset - (-1f)) / (1f - (-1f)) * (1f - 0f) + 0f
val alpha = MathUtils.lerp(0f, 255f, offset * baseAlpha).toInt()
val color = Color.argb(alpha, baseColor.red, baseColor.green, baseColor.blue)
scrim.setBackgroundColor(color)
}
override fun onStateChanged(bottomSheet: View, newState: Int) {
}
})
For more information on bottom app bars see the documentation.
Navigation drawers support Material Theming and can be customized in terms of color, typography and shape.
API and source code:
NavigationView
The following example shows a navigation drawer with Material Theming.
Using theme attributes, default style theme attributes, and styles in
res/values/styles.xml
(themes all navigation drawers and affects other
components):
<style name="Theme.App" parent="Theme.MaterialComponents.*">
...
<item name="colorPrimary">@color/shrine_pink_100</item>
<item name="colorSurface">@color/shrine_pink_50</item>
<item name="colorOnSurface">@color/shrine_pink_900</item>
<item name="textAppearanceHeadline6">@style/TextAppearance.App.Headline6</item>
<item name="textAppearanceSubtitle2">@style/TextAppearance.App.Subtitle2</item>
<item name="textAppearanceBody2">@style/TextAppearance.App.Body2</item>
<item name="shapeAppearanceSmallComponent">@style/ShapeAppearance.App.SmallComponent</item>
<item name="navigationViewStyle">@style/Widget.App.NavigationView</item>
</style>
<style name="TextAppearance.App.Headline6" parent="TextAppearance.MaterialComponents.Subtitle1">
<item name="fontFamily">@font/rubik</item>
<item name="android:fontFamily">@font/rubik</item>
</style>
<style name="TextAppearance.App.Subtitle2" parent="TextAppearance.MaterialComponents.Subtitle1">
<item name="fontFamily">@font/rubik</item>
<item name="android:fontFamily">@font/rubik</item>
</style>
<style name="TextAppearance.App.Body2" parent="TextAppearance.MaterialComponents.Subtitle1">
<item name="fontFamily">@font/rubik</item>
<item name="android:fontFamily">@font/rubik</item>
</style>
<style name="ShapeAppearance.App.SmallComponent" parent="ShapeAppearance.MaterialComponents.SmallComponent">
<item name="cornerFamily">cut</item>
<item name="cornerSize">4dp</item>
</style>
<style name="Widget.App.NavigationView" parent="Widget.MaterialComponents.NavigationView">
<item name="itemIconTint">@color/navigation_item_color</item>
<item name="itemTextColor">@color/navigation_item_color</item>
<item name="itemShapeFillColor">@color/navigation_item_background_color</item>
</style>
In res/color/navigation_item_color.xml
:
<selector ...>
<item android:color="?attr/colorOnSurface" android:state_checked="true"/>
<item android:alpha="@dimen/material_emphasis_disabled" android:color="?attr/colorOnSurface" android:state_enabled="false"/>
<item android:alpha="@dimen/material_emphasis_medium" android:color="?attr/colorOnSurface"/>
</selector>
In res/color/navigation_item_background_color.xml
:
<selector ...>
<item android:alpha="@dimen/material_emphasis_disabled" android:color="?attr/colorPrimary" android:state_activated="true"/>
<item android:alpha="@dimen/material_emphasis_disabled" android:color="?attr/colorPrimary" android:state_checked="true"/>
<item android:color="@android:color/transparent"/>
</selector>
or using default style theme attributes, styles and theme overlays (themes all navigation drawers but does not affect other components):
<style name="Theme.App" parent="Theme.MaterialComponents.*">
...
<item name="navigationViewStyle">@style/Widget.App.NavigationView</item>
</style>
<style name="Widget.App.NavigationView" parent="Widget.MaterialComponents.NavigationView">
<item name="materialThemeOverlay">@style/ThemeOverlay.App.NavigationView</item>
<item name="itemIconTint">@color/navigation_item_color</item>
<item name="itemTextColor">@color/navigation_item_color</item>
<item name="itemShapeFillColor">@color/navigation_item_background_color</item>
</style>
<style name="ThemeOverlay.App.NavigationView" parent="">
<item name="colorPrimary">@color/shrine_pink_100</item>
<item name="colorSurface">@color/shrine_pink_50</item>
<item name="colorOnSurface">@color/shrine_pink_900</item>
<item name="textAppearanceHeadline6">@style/TextAppearance.App.Headline6</item>
<item name="textAppearanceSubtitle2">@style/TextAppearance.App.Subtitle2</item>
<item name="textAppearanceBody2">@style/TextAppearance.App.Body2</item>
<item name="shapeAppearanceSmallComponent">@style/ShapeAppearance.App.SmallComponent</item>
</style>
or using the style in the layout (affects only this navigation drawer):
<com.google.android.material.navigation.NavigationView
...
style="@style/Widget.App.NavigationView" />