Its been a while since Google introduced Material Design, but recently with Design Support Library v25 they released a new widget to make an Android Bottom Navigation Bar, as described in the official material design specs. This new navigation component is called the BottomNavigationView and as mentioned, its packaged under the design support library, having full backward support. Although if you browse the internet, you may find many examples, showing how to implement an Android bottom navigation bar. But this new Android BottomNavigationView widget makes it very easy for the developers to build and deploy apps with bottom navigation, as its an official component.
Android BottomNavigationView Widget
At first when you look at the new BottomNavigationView widget it may look similar to the TabLayout
of the same library. But but do not get confused, as its implementation is a lot different than that of the later one. As the new bottom bar navigation implementation of Android is based out of menu items. Hence to populate a BottomNavigationView
you need to specify a menu resource file, unlike in the TabLayout
. Although if you look at the final output i.e. the screen, there is still a striking similarity between the two. But putting this discussion to rest, lets have a look at the new features of the Android BottomNavigationView.
Whenever a new component is introduced, along with it some new methods and attributes are also added with it. Hence with the Android’s official bottom navigation widget the BottomNavigationView following new XML attributes are added:
android.support.design:itemBackground – It is used to set the background color of the navigation item. It does not take a ColorStateList, as per design specifications.
android.support.design:itemIconTint – It is used to set the icon tint color, use a ColorStateList to specify colors for all states.
android.support.design:itemTextColor – It is used to set the text color of the navigation item, use a ColorStateList to specify colors for all states.
As I mentioned BottomNavigationView
takes a menu resource file to inflate the navigation items. To do so following are the ways in which it can be done:
Once a BottomNavigationView
is inflated and visible, a click listener can be attached to it:
Method used to select a specific item in the BottomNavigationView:
BottomNavigationView.getMenu().getItem(index).setChecked(true);
Although this component gives us the flexibility of changing screen content dynamically. But it is advised to not implement swiping views with an Android bottom navigation bar as per specs. Therefore this rules out the possibility of using a ViewPager with the bottom navigation bar. Instead a simple view or a set of fragments for complex implementation can be used. Therefore here in this tutorial, I will show how to implement a BottomNavigationView with a set of fragments. Lets have look at the example below.
Android Bottom Navigation Bar Example
To demonstrate a working example of Android BottomNavigationView widget, I would make three fragments and switch between them by using the bottom navigation bar. Here are the steps:
Step 1 : Add the dependencies
To start off with an example of bottom navigation bar on android , first we need to include following dependencies in our build.gradle file.
compile 'com.android.support:appcompat-v7:25.1.0' compile 'com.android.support:design:25.1.0' compile 'com.android.support:support-v4:25.1.0'
Step 2 : Define the Fragments
For this example I will be building a screen with three fragments, which could be switched by the BottomNavigationView. Hence before jumping on to the main screen, lets define three fragments.
Fragment 1:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.truiton.bottomnavigation.ItemOneFragment"> <ImageView android:id="@+id/truiton_image" android:layout_width="300dp" android:layout_height="300dp" android:layout_centerInParent="true" android:src="@mipmap/truiton"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/truiton_image" android:layout_centerHorizontal="true" android:text="Fragment 1" android:textSize="30sp"/> </RelativeLayout>
package com.truiton.bottomnavigation; import android.os.Bundle; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; public class ItemOneFragment extends Fragment { public static ItemOneFragment newInstance() { ItemOneFragment fragment = new ItemOneFragment(); return fragment; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_item_one, container, false); } }
Fragment 2:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.truiton.bottomnavigation.ItemTwoFragment"> <ImageView android:id="@+id/truiton_image" android:layout_width="300dp" android:layout_height="300dp" android:layout_centerInParent="true" android:src="@mipmap/truiton"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/truiton_image" android:layout_centerHorizontal="true" android:text="Fragment 2" android:textSize="30sp"/> </RelativeLayout>
package com.truiton.bottomnavigation; import android.os.Bundle; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; public class ItemTwoFragment extends Fragment { public static ItemTwoFragment newInstance() { ItemTwoFragment fragment = new ItemTwoFragment(); return fragment; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_item_two, container, false); } }
Fragment 3:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.truiton.bottomnavigation.ItemThreeFragment"> <ImageView android:id="@+id/truiton_image" android:layout_width="300dp" android:layout_height="300dp" android:layout_centerInParent="true" android:src="@mipmap/truiton"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/truiton_image" android:layout_centerHorizontal="true" android:text="Fragment 3" android:textSize="30sp"/> </RelativeLayout>
package com.truiton.bottomnavigation; import android.os.Bundle; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; public class ItemThreeFragment extends Fragment { public static ItemThreeFragment newInstance() { ItemThreeFragment fragment = new ItemThreeFragment(); return fragment; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_item_three, container, false); } }
Step 3 : Defining the bottom navigation menu XML
As mentioned before to populate the actual items into an Android bottom navigation bar, a menu type XML is used. This XML should contain at minimum three attributes:
- android:title
- android:icon
- android:id
For this example of BottomNavigationView, I would make a menu of three items:
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/action_item1" android:icon="@drawable/ic_account_box_black_24dp" android:title="@string/item_1"/> <item android:id="@+id/action_item2" android:icon="@drawable/ic_account_circle_black_24dp" android:title="@string/item_2"/> <item android:id="@+id/action_item3" android:icon="@drawable/ic_assignment_ind_black_24dp" android:title="@string/item_3"/> </menu>
Step 4 : Defining the Activity XML
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout android:id="@+id/activity_main" 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:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.truiton.bottomnavigation.MainActivity"> <FrameLayout android:id="@+id/frame_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_above="@+id/navigation" android:animateLayoutChanges="true"> </FrameLayout> <android.support.design.widget.BottomNavigationView android:id="@+id/navigation" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:background="@color/colorPrimary" app:itemIconTint="@color/nav_item_state_list" app:itemTextColor="@color/nav_item_state_list" app:menu="@menu/bottom_navigation_items"/> </RelativeLayout>
As you can see above, for attributes app:itemIconTint
and app:itemTextColor
, I have used a ColorStateList. Please make sure when you make a color state list, its according to the Material design specs for bottom navigation bar. Full source code is available at the end of the tutorial.
Step 5 : Defining the activity with bottom navigation bar
package com.truiton.bottomnavigation; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.design.widget.BottomNavigationView; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentTransaction; import android.support.v7.app.AppCompatActivity; import android.view.MenuItem; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); BottomNavigationView bottomNavigationView = (BottomNavigationView) findViewById(R.id.navigation); bottomNavigationView.setOnNavigationItemSelectedListener (new BottomNavigationView.OnNavigationItemSelectedListener() { @Override public boolean onNavigationItemSelected(@NonNull MenuItem item) { Fragment selectedFragment = null; switch (item.getItemId()) { case R.id.action_item1: selectedFragment = ItemOneFragment.newInstance(); break; case R.id.action_item2: selectedFragment = ItemTwoFragment.newInstance(); break; case R.id.action_item3: selectedFragment = ItemThreeFragment.newInstance(); break; } FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); transaction.replace(R.id.frame_layout, selectedFragment); transaction.commit(); return true; } }); //Manually displaying the first fragment - one time only FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); transaction.replace(R.id.frame_layout, ItemOneFragment.newInstance()); transaction.commit(); //Used to select an item programmatically //bottomNavigationView.getMenu().getItem(2).setChecked(true); } }
As you can see above when making a screen with the help of BottomNavigationView we have to initialize it with a default view. As there is no ViewPager
here, we are doing it all manually. By default when a BottomNavigationView
is initialized it is loaded with the first item selected. But if you wish to load the screen with any other item selected, you can do so by getting the menu item and setting it checked as shown above. For full source code, please refer to the following link:
The final output would look like this:
BottomNavigationView Limitations
Although the view itself is recently released, hence it is bound to have some issues. But if you are trying to build an Android screen with bottom navigation, here is a list of issues you might face:
- Item Background cannot be colored for selected state.
- It does not have a bottom navigation behavior, hence no integration is available for FAB, Snackbar, and CoordinatorLayout.
- Ethically swiping of views should not be done – Stated in Material Design guidelines.
- Text and icon sizes cannot be changed.
- No way to hide title for non selected items.
- Only 5 items can be added at a time.
But besides all this, building an Android bottom navigation bar has become a lot more simpler with the new BottomNavigationBar widget. As this is the new official component for bottom navigation. Also when speaking of shaping a product, giving upfront options like the bottom navigation has always gotten more traction, since it presents all the options to a user right away. Hope this helped, follow us on Twitter, Facebook and Google+ for more updates.
Born in New Delhi, India. A software engineer by profession, an android enthusiast and an evangelist. My motive here is to create a group of skilled developers, who can develop something new and good. Reason being programming is my passion, and also it feels good to make a device do something you want. In a very short span of time professionally I have worked with many tech firms. As of now too, I am employed as a senior engineer in a leading tech company. In total I may have worked on more than 20 projects professionally, and whenever I get spare time I share my thoughts here at Truiton.
thanks nice. how to implement the back navigation on back press (e.g item1 -> item2 -> item3 then back item3 -> item2 – item1)
above transaction.commit() Line add this Line
transaction.addToBackStack(null);
im not sure about right Spelling addToBackStack …
I had search many topic related to bottom navigation bar and i tried to implement on my project exactly as per there instructions. but then i found your blog and i am so happy that your tutorial works and the way to guide it so easy to understand. thank you so much bro, have a good and blessing day…
Hi sir, how to add RecyclerView in the first fragment?
thanks 😀
Hi,
Please refer to this tutorial:
https://www.truiton.com/2015/02/android-recyclerview-tutorial/
-Mohit Gupt
thankss dude it worked fine…
how to add badge counter on it
Thank you very much. This is the only example that worked. Thanks again.
Very nice tutorial. Thanks Mohit
But why I don’t see the standard behavior here where the text is shown only in the case of the currect selected bottom icon?
Simply brilliant , thanks for this clear example.
Thank you for the very useful tutorial.
How to disable Shift mode for each item
You need to use viewhelper class.
package com.truiton.bottomnavigation;
import android.support.design.internal.BottomNavigationItemView;
import android.support.design.internal.BottomNavigationMenuView;
import android.support.design.widget.BottomNavigationView;
import android.util.Log;
import java.lang.reflect.Field;
/**
* Helper class to get rid of "Shift Mode" from BottomNavigationView
*/
public class bh {
public static void disableShiftMode(BottomNavigationView view) {
BottomNavigationMenuView menuView = (BottomNavigationMenuView) view.getChildAt(0);
try {
Field shiftingMode = menuView.getClass().getDeclaredField("mShiftingMode");
shiftingMode.setAccessible(true);
shiftingMode.setBoolean(menuView, false);
shiftingMode.setAccessible(false);
for (int i = 0; i < menuView.getChildCount(); i++) {
BottomNavigationItemView item = (BottomNavigationItemView) menuView.getChildAt(i);
//noinspection RestrictedApi
item.setShiftingMode(false);
// set once again checked value, so view will be updated
//noinspection RestrictedApi
item.setChecked(item.getItemData().isChecked());
}
} catch (NoSuchFieldException e) {
Log.e("BNVHelper", "Unable to get shift mode field", e);
} catch (IllegalAccessException e) {
Log.e("BNVHelper", "Unable to change value of shift mode", e);
}
}
}
Thank you for this great tutorial. I started off with yours, and wanted to add two more items so that there will be 5 total. Once I added 5 items, when I click it on the phone, they animate and the icon clicked is larger and they slide slightly. While this is a nice animation, I would prefer them to be fixed and not moving/changing when clicked except for color which you have. Any suggestions? Thanks!
Thanks for this article…
Hey Mohit, Thanks for the clear illustration, can you add the stack management for each single tab, in the same or any clues regarding to this?
Thanks a lot, a very clear tutorial that helped me a bunch!
thanks for the good example, i am getting one issue that on bottom navigation I am not getting the name for un-selected menu item. Only first item get selected by default and its name is visible
thank you.this example worked very well.