UPDATE 2016.10.26.####
Added a paragraph after the list of available attributes for the control to mention how you can have a ripple effect as touch highlight if you don't set the background of the BottomNavigationView widget.
Original post####
Bottom navigation with tabs has been quite a common primary navigation pattern over on iOS for a long time. While it is a little alien for many Android users, it has several merits. First of all, it sits at the bottom of the screen so it is easy to reach even while using the phone with one hand. It is always visible, making it easier to explore compared to say a Navigation Drawer. Android guidelines already included tabs too, but they were at the top of the screen, combined with swipeable pages, implemented with a ViewPager.
This spring, Google officially added Bottom Navigation to Material Design Guidelines and released new versions of its Photos and Google+ app with this component as its main navigation. The only problem was - as it is the case with many items in the spec - that there were no official implementation available for developers for this component. Third party libraries appeared soon, but the developer community wanted a solution from Google and it took them this long to release it - but it is finally here.
It is included in the Design Support Library, starting with version 25.0.0. You can include it in your build.gradle
file with the following line (you'll also need the AppCompat Support Library as the Design Support Library's dependency):
compile 'com.android.support:appcompat-v7:25.0.0'
compile 'com.android.support:design:25.0.0'
For this article I demonstrate a basic usage of the widget. I also made a demo app which you can check out here:
https://github.com/AutSoft/BottomNavigationTest
The Design Spec
The design spec outlines a couple of traits for this component, most importantly:
- It should be used for three to five top level destinations which require instant access.
- They should have a light or dark grayscale background with colored icons and text, or a colored background and light or dark grayscale icons - you should not mix those and you should only use at most one color for the tabs
- Short text labels should be displayed below every icon and tapping one of them should take you to one of the pages.
- Contrary to (top) tabs, swiping between these pages should not be enabled - great when the content of the page requires the gesture for something else.
- The currently selected tab should be highlighted with bigger icon and text and/or different coloring.
- Tapping on a tab could colour the whole view with a new tint color using a ripple effect
You can read the corresponding section of the spec here:
https://material.google.com/components/bottom-navigation.html
The Widget
As I mentioned and official implementation is included in the latest Design Support Library. The documentation for it is pretty scarse and in some places even wrong at this time (though I expect it to improve). You can find it here:
https://developer.android.com/reference/android/support/design/widget/BottomNavigationView.html
It includes a basic example for including it in your layout
resource file but it is misleading at the time of this writing, so here is a fixed version of it:
<android.support.design.widget.BottomNavigationView
xmlns_app="http://schemas.android.com/apk/res-auto"
android_id="@+id/bottom_navigation_view"
android_layout_width="match_parent"
android_layout_height="wrap_content"
app_itemBackground="@color/darkGrey"
app_itemIconTint="@color/bottom_navigation_item_background_colors"
app_itemTextColor="@color/bottom_navigation_item_background_colors"
app_menu="@menu/menu_bottom_navigation" />
It only has three xml attributes at this time:
- itemBackground: The background color or
Drawable
of the items. Can be set from code with thesetItemBackgroundResource()
method - itemIconTint: The icon tint for items Can be set from code with the
setItemIconTintList()
method - itemTextColor: The text color for the item labels Can be set from code with the
setItemTextColor()
method
If you does not specify these attributes, the currently selected item's icon and text automatically colored with the color you specified in your app theme as colorPrimary
(the other items are tinted grey) and you also get a ripple effect on touch. There does not seem to be a way to get this ripple effect when you change the background though.
It can be populated with items via a menu
resource file, just like a Navigation Drawer or an Overflow menu. Please note that you can set the enabled state for each items but you cannot set the visibility of them from the menu resource file. Here is an example:
<?xml version="1.0" encoding="utf-8"?>
<menu
xmlns_android="http://schemas.android.com/apk/res/android">
<item
android_id="@+id/action_one"
android_icon="@android:drawable/ic_dialog_map"
android_title="One"/>
<item
android_id="@+id/action_two"
android_icon="@android:drawable/ic_dialog_info"
android_title="Two"/>
<item
android_id="@+id/action_three"
android_icon="@android:drawable/ic_dialog_email"
android_title="Three"/>
<item
android_id="@+id/action_four"
android_icon="@android:drawable/ic_popup_reminder"
android_title="Four"/>
</menu>
The menu can be inflated from code too, with the inflateMenu()
method.
It is smart about displaying these items, as if there is more than three elements, it only displays the currently selected one with icon AND text, and shifts the other ones closer together without text labels. Sadly, there isn't any way to force enable or disable this behaviour which may not work with every design. It also doesn't allow populating the Bottom Navigation View with more than five items - as per the design spec (it throws an IllegalArgumentException
if you try to).
To achieve different tinting for selected items, you should specify a color list
resource as itemBackground
and itemTextColor
like this:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns_android="http://schemas.android.com/apk/res/android">
<item
android_color="@color/colorAccent"
android_state_checked="false"/>
<item
android_color="@android:color/white"
android_state_checked="true"/>
</selector>
Finally, you can listen to tab selection events by adding an BottomNavigation.OnNavigationItemSelectedListener
via the setOnNavigationItemSelectedListener()
method:
bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
Fragment fragment = null;
switch (item.getItemId()) {
case R.id.action_one:
// Switch to page one
break;
case R.id.action_two:
// Switch to page two
break;
case R.id.action_three:
// Switch to page three
break;
}
return true;
}
});
The selected item will appear selected if you return true for the onNavigationItemSelected()
method.
That's all we get for now, there is no sign of the color ripple effect or the left navigation variant which are also part of the design spec.
At the time of writing, some of the third party libraries still provide much more functionality and customization, so they may be worth checking out:
https://github.com/Ashok-Varma/BottomNavigation
https://github.com/sephiroth74/Material-BottomNavigation
https://github.com/roughike/BottomBar
https://github.com/aurelhubert/ahbottomnavigation