Bottom navigation bars allow movement between primary destinations in an app.
Contents
Before you can use the Material bottom navigation, you need to add a dependency to the Material Components for Android library. For more information, go to the Getting started page.
A typical layout would look something like this:
<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="wrap_content">
...
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/bottom_navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:menu="@menu/bottom_navigation_menu" />
</LinearLayout>
The @menu/bottom_navigation_menu
resource should point to a file named
bottom_navigation_menu.xml
inside a menu
resource directory:
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/page_1"
android:enabled="true"
android:icon="@drawable/icon_1"
android:title="@string/text_label_1"/>
<item
android:id="@+id/page_2"
android:enabled="true"
android:icon="@drawable/icon_2"
android:title="@string/text_label_2"/>
</menu>
Note: BottomNavigationView
does not support more than 5 menu
items.
In code:
BottomNavigationView.OnNavigationItemSelectedListener { item ->
when(item.itemId) {
R.id.item1 -> {
// Respond to navigation item 1 click
true
}
R.id.item2 -> {
// Respond to navigation item 2 click
true
}
else -> false
}
}
There's also a method for detecting when navigation items have been reselected:
bottomNavigation.setOnNavigationItemReselectedListener { item ->
when(item.itemId) {
R.id.item1 -> {
// Respond to navigation item 1 reselection
}
R.id.item2 -> {
// Respond to navigation item 2 reselection
}
}
}
That results in:
Note: We have deprecated the
BottomNavigationView#setOnNavigationItemSelectedListener
and
BottomNavigationView#setOnNavigationItemReselectedListener
methods in favor of
the listeners in NavigationBarView
. This allows you to share selection
handling code between the BottomNavigation
and NavigationRail
view elements.
You should set an android:title
for each of your menu
items so that screen
readers like TalkBack can properly announce what each navigation item
represents:
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
...
android:title="@string/text_label"/>
...
</menu>
The labelVisibilityMode
attribute can be used to adjust the behavior of the
text labels for each navigation item. There are four visibility modes:
LABEL_VISIBILITY_AUTO
(default): The label behaves as “labeled” when there are 3 items or less, or “selected” when there are 4 items or moreLABEL_VISIBILITY_SELECTED
: The label is only shown on the selected navigation itemLABEL_VISIBILITY_LABELED
: The label is shown on all navigation itemsLABEL_VISIBILITY_UNLABELED
: The label is hidden for all navigation items
Initialize and show a BadgeDrawable
associated with menuItemId
, subsequent
calls to this method will reuse the existing BadgeDrawable
:
var badge = bottomNavigation.getOrCreateBadge(menuItemId)
badge.isVisible = true
// An icon only badge will be displayed unless a number is set:
badge.number = 99
As a best practice if you need to temporarily hide the badge (e.g. until the
next notification is received), change the visibility of BadgeDrawable
:
val badgeDrawable = bottomNavigation.getBadge(menuItemId)
if (badgeDrawable != null) {
badgeDrawable.isVisible = false
badgeDrawable.clearNumber()
}
To remove any BadgeDrawable
s that are no longer needed:
bottomNavigation.removeBadge(menuItemId)
See the BadgeDrawable
documentation for more information
about badges.
API and source code:
BottomNavigationView
The following example shows a bottom navigation bar with four icons:
- Favorites
- Music note
- Places
- News
In layout.xml
:
<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="wrap_content">
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/bottom_navigation"
style="@style/Widget.MaterialComponents.BottomNavigationView.Colored"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:menu="@menu/bottom_navigation_menu" />
</LinearLayout>
In bottom_navigation_menu.xml
inside a menu
resource directory:
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/page_1"
android:enabled="true"
android:icon="@drawable/ic_favorite"
android:title="@string/favorites"/>
<item
android:id="@+id/page_2"
android:enabled="true"
android:icon="@drawable/ic_music"
android:title="@string/music"/>
<item
android:id="@+id/page_3"
android:enabled="true"
android:icon="@drawable/ic_places"
android:title="@string/places"/>
<item
android:id="@+id/page_4"
android:enabled="true"
android:icon="@drawable/ic_news"
android:title="@string/news"/>
</menu>
In code:
bottomNavigation.selectedItemId = R.id.page_2
The following is an anatomy diagram for the bottom navigation bar:
- (1) Container
- Navigation items:
- (2) Inactive icon
- (3) Inactive text label
- (4) Active icon
- (5) Active text label
Element | Attribute | Related methods | Default value |
---|---|---|---|
Color | app:backgroundTint |
N/A | ?attr/colorSurface |
Elevation | app:elevation |
setElevation |
8dp |
Element | Attribute | Related methods | Default value |
---|---|---|---|
Menu resource | app:menu |
inflateMenu getMenu |
N/A |
Ripple (inactive) | app:itemRippleColor |
setItemRippleColor getItemRippleColor |
?attr/colorOnSurface at 8% (see all states) |
Ripple (active) | " | " | ?attr/colorPrimary at 8% (see all states) |
Label visibility mode | app:labelVisibilityMode |
setLabelVisibilityMode getLabelVisibilityMode |
LABEL_VISIBILITY_AUTO |
Element | Attribute | Related methods | Default value |
---|---|---|---|
Icon | android:icon in the menu resource |
N/A | N/A |
Size | app:itemIconSize |
setItemIconSize setItemIconSizeRes getItemIconSize |
24dp |
Color (inactive) | app:itemIconTint |
setItemIconTintList getItemIconTintList |
?attr/colorOnSurface at 60% |
Color (active) | " | " | ?attr/colorPrimary |
Element | Attribute | Related methods | Default value |
---|---|---|---|
Text label | android:title in the menu resource |
N/A | N/A |
Color (inactive) | app:itemTextColor |
setItemTextColor getItemTextColor |
?attr/colorOnSurface at 60% |
Color (active) | " | " | ?attr/colorPrimary |
Typography (inactive) | app:itemTextAppearanceInactive |
setItemTextAppearanceInactive getItemTextAppearanceInactive |
?attr/textAppearanceCaption |
Typography (active) | app:itemTextAppearanceActive |
setItemTextAppearanceActive getItemTextAppearanceActive |
?attr/textAppearanceCaption |
Element | Style | Container color | Icon/Text label color (inactive) | Icon/Text label color (active) |
---|---|---|---|---|
Default style | Widget.MaterialComponents.BottomNavigationView |
?attr/colorSurface |
?attr/colorOnSurface at 60% |
?attr/colorPrimary |
Colored style | Widget.MaterialComponents.BottomNavigationView.Colored |
?attr/colorPrimary |
?attr/colorOnPrimary at 60% |
?attr/colorOnPrimary |
Dark theme supported style | Widget.MaterialComponents.BottomNavigationView.PrimarySurface |
?attr/colorPrimary in light theme?attr/colorSurface in dark theme |
?attr/colorOnPrimary at 60% in light theme?attr/colorOnSurface at 60% in light theme |
?attr/colorOnPrimary in light theme?attr/colorPrimary in dark theme |
Default style theme attribute: ?attr/bottomNavigationStyle
Note: The Widget.MaterialComponents.BottomNavigationView.PrimarySurface
style will automatically switch between between the component's primary colored
style in light theme and surface colored style in dark theme. More information
in the
Dark theme documentation.
See the full list of styles, navigation bar attributes, and bottom navigation attributes.
Bottom navigation supports Material Theming and can be customized in terms of color and typography.
API and source code:
BottomNavigationView
The following example shows a bottom navigation bar with Material Theming.
Using theme attributes and a style in res/values/styles.xml
(themes all bottom
navigation bars and affects other components):
<style name="Theme.App" parent="Theme.MaterialComponents.*">
...
<item name="bottomNavigationStyle">@style/Widget.MaterialComponents.BottomNavigationView.Colored</item>
<item name="colorPrimary">@color/shrine_pink_100</item>
<item name="colorOnPrimary">@color/shrine_pink_900</item>
</style>
Or using a default style theme attribute, styles, and a theme overlay (themes all bottom navigation bars but does not affect other components):
<style name="Theme.App" parent="Theme.MaterialComponents.*">
...
<item name="bottomNavigationStyle">@style/Widget.App.BottomNavigationView</item>
</style>
<style name="Widget.App.BottomNavigationView" parent="Widget.MaterialComponents.BottomNavigationView.Colored">
<item name="materialThemeOverlay">@style/ThemeOverlay.App.BottomNavigationView</item>
</style>
<style name="ThemeOverlay.App.BottomNavigationView" parent="">
<item name="colorPrimary">@color/shrine_pink_100</item>
<item name="colorOnPrimary">@color/shrine_pink_900</item>
</style>
Or using the style in the layout (affects only this specific bottom navigation bar):
<com.google.android.material.bottomnavigation.BottomNavigationView
...
style="@style/Widget.App.BottomNavigationView"
/>