Using Bottom Navigation View – Android Design Support Library

Android Bottom Bar (Bottom Navigation View) was officially added in Design Support Library v25. Bottom Bar was first introduced in the Material Design guidelines.

Initially, it was met with some reception. People had polarizing opinions on it. Even I, was on the negative spectrum of thought.The fact that it had existed on iOS for so long, now felt like a poor rip-off for Android.

However, usability studies say that Bottom Navigation trumps the Navigation Drawer. That’s when I felt its introduction was actually, well thought of.

But irrespective of our opinions, Bottom Navigation is here to stay. It is now officially supported in Android’s Design Support Library, as of version 25.0.0.

Bottom Navigation Bar – Getting Started

Bottom navigation bars make it easy to explore and switch between top-level views in a single tap. – material.io

Bottom Navigation in Google+ app

Bottom Navigation in Instagram Android app

Some of you might wonder why I’m writing another post on Bottom Navigation.

When Bottom Navigation was added to the Material Design spec, there was no official support for it. This paved way for (unofficial) third-party libraries.

Now I’m not saying those libraries are bad in any way. Those who know me, will know that I encourage using third-party libraries when possible.

However, the Design Support Library is so popular, chances are that you’re already using it. Since it now includes Bottom Navigation, it makes little sense to rely on third-party.

With that said, let’s proceed with creating a Bottom Navigation Bar using Android Design Support Library.

Limitations – A word of caution

Before we actually start, thought I’ll give you a quick heads up. The BottomNavigationView in Design Support Library is limited in many ways.

Here is what’s known:

icon icon

I thought it would be a good idea to tell you BEFORE we proceed. It will be pointless to tell you this after you’ve read this entire article.

So if any of these limitations are a deal-breaker, then stop reading this article right now!

Currently, third-party libraries offer much more customizations. In fact, I’ve written an article about Bottom Navigation, using a highly customizable third-party library. It also tells you when to use Bottom Navigation and the difference with Navigation Drawer.

So if you want complete customization with translation behaviors, that is your go to article.

For those who want a simple implementation using Android’s support libraries, read on.

Adding Dependencies

Start by adding the relevant support library dependencies.

dependencies {
    ...
    compile 'com.android.support:design:25.1.0'
    // Other Dependencies
}

 Adding BottomNavigationView to Layout

Now, add the Bottom Bar to your layout.xml.

<android.support.design.widget.BottomNavigationView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"
        app:itemBackground="?attr/colorPrimary"
        app:itemIconTint="@android:color/white"
        app:itemTextColor="@android:color/white"
        app:menu="@menu/bottombar_menu"/>

I’ve taken the liberty to add some basic styling here. As you can see, we’re allowed to set a few basic color properties.

Adding Bottom Navigation Items

Create a new bottombar_menu.xml under …res/menu/.

bottombar_menu.xml

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:app="http://schemas.android.com/apk/res-auto">

     <item
        android:id="@+id/bottombaritem_calls"
        android:icon="@drawable/ic_call_24dp"
        android:title="Calls"
        app:showAsAction="ifRoom"/>

    <item
        android:id="@+id/bottombaritem_recents"
        android:icon="@drawable/ic_query_builder_24dp"
        android:title="Recents"
        app:showAsAction="ifRoom"/>

    <item
        android:id="@+id/bottombaritem_trips"
        android:icon="@drawable/ic_flight_24dp"
        android:title="Trips"
        app:showAsAction="ifRoom"/>

</menu>

NOTE:
It is recommended to have at least 3, and at most 5 items in Bottom Navigation.


Connecting Bottom Navigation in Activity.java

Head over to your Activity.java. Initialize your UI.

public class BottomBarActivity extends AppCompatActivity {

    private BottomNavigationView bottomNavigationView;
    ...

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_bottom_bar);

        bottomNavigationView = (BottomNavigationView) findViewById(R.id.bottom_nav);

      ...
    }
  ...
}

 Listen for Item clicks

We can listen and react to individual item clicks of Bottom Navigation. We do this using BottomNavigationView. setOnNavigationItemSelectedListener().

bottomNavigationView.setOnNavigationItemSelectedListener(
                new BottomNavigationView.OnNavigationItemSelectedListener() {
                    @Override
                    public boolean onNavigationItemSelected(@NonNull MenuItem item) {
                        switch (item.getItemId()) {
                            case R.id.action_bottombar_calls:
                                // TODO
                                return true;
                            case R.id.action_bottombar_recents:
                                // TODO
                                return true;
                            case R.id.action_bottombar_trips:
                                // TODO
                                return true;
                        }
                        return false;
                    }
                });

Now we have a basic Bottom Navigation set up for our app. Why not run it and see how it looks?

Our Bottom Navigation seems to register clicks. But something seems off. Did you notice?

Our very first navigation item ‘Calls’ is selected by default alright.

But something doesn’t seem right

I don’t know about you, but I don’t see any state difference.

Meaning, visually, there’s hardly any difference between items that are resting, and the active item. In short, there is not enough visual contrast to differentiate the two.

Take a good look at our Bottom Navigation. Now see how it looks like on the Material Docs.

Image credit – material.io

Surely both don’t look the same! :/

Something has to be done about that. We can quickly take care of this by using XML selectors.

Bottom Navigation Styling – Selector States

Create selector_bottombar_item.xml under …res/drawable/.

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:color="?attr/colorPrimaryDark" android:state_enabled="false"/>
    <item android:color="@android:color/white" android:state_checked="true"/>
    <item android:color="@color/white_70"/>
</selector>

Modify your Activity’s BottomNavigationView widget to use this selector.

iconicon
...  
    <android.support.design.widget.BottomNavigationView
        android:id="@+id/bottom_nav"
      ...
        app:itemIconTint="@drawable/selector_bottombar_item"
        app:itemTextColor="@drawable/selector_bottombar_item"
        app:menu="@menu/bottombar_menu"/>
...

Run your app again.

This looks much better doesn’t it? The active and default states are now clearly visible.

But there’s still one thing amiss. Take a look at the Bottom Navigation images in material.io. The default (resting) state items don’t display text.

Selector States for Bottom Navigation Text

Now keep in mind that this is not mandatory. If you want text visible for all items, then just ignore this and move on to the next section. But for those who want to achieve this effect, read on.

Create another selector …res/drawable/selector_bottombar_text.xml.

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:color="?attr/colorPrimaryDark" android:state_enabled="false"/>
    <item android:color="@android:color/white" android:state_checked="true"/>
    <item android:color="?attr/colorPrimary"/>
</selector>

Update your BottomNavigationView XML layout to reflect this new selector.

...
<android.support.design.widget.BottomNavigationView
        ...
        app:itemTextColor="@drawable/selector_bottombar_text"
        app:menu="@menu/bottombar_menu"/>
...

Run your app again.

Much better right?

Before moving onto the next section, why don’t you take a breather?


Creating Screens for Bottom Navigation Items

If you recall the guidelines, BottomNavigationView navigates between top-level views.

Think carefully, the top-level view(s) here would be the visible space above the Bottom Navigation.

This visible space must reflect the currently active Bottom Navigation Item.

So if the ‘Calls’ item is currently active (highlighted or selected) in our Bottom Navigation, then the visible space must show the Calls screen.

We can do this using Fragment.

Let’s hook up our BottomNavigationView with some Fragments.

Creating Fragments

For simplicity, I will use a single Fragment, with slight UI changes that denote each navigation item.

Create class BottomBarFragment.java. The only thing that I’ll be doing here is include a TextView. It will reflect the name of the current Bottom Navigation item.

public class BottomBarFragment extends Fragment {
    public static final String ARG_TITLE = "arg_title";
    private TextView textView;

    ...

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_bottom_bar, container, false);

        textView = (TextView) rootView.findViewById(R.id.fragment_bottom_bar_text_activetab);

        String title = getArguments().getString(ARG_TITLE, "");
        textView.setText(title);
      ...
        return rootView;
    }

}

Layout Design
Here’s what I’ve created. Something simple enough where the TextView denotes the current active navigation item.

fragment_bottom_bar.xml

Modifying Activity layout to support Fragments

Go back to your Activity’s XML layout. We need a FrameLayout that will host our Fragment.

<FrameLayout>

    <FrameLayout
        android:id="@+id/frame_fragmentholder"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginBottom="?attr/actionBarSize"/>

    <android.support.design.widget.BottomNavigationView	/>

</FrameLayout>

 Inflating Fragments

Go back to BottomBarActivity.java. We need to do 2 things.

1. Build a list of our Fragments. One for each Navigation item

Declare a List<BottomBarFragment> of Fragments that will hold all the Fragments for our Bottom Navigation.

private List<BottomBarFragment> fragments = new ArrayList<>(3);

We need a List of size 3 since our Bottom Navigation contains 3 items.

private void buildFragmentsList() {
        BottomBarFragment callsFragment = buildFragment("Calls");
        BottomBarFragment recentsFragment = buildFragment("Recents");
        BottomBarFragment tripsFragment = buildFragment("Trips");

        fragments.add(callsFragment);
        fragments.add(recentsFragment);
        fragments.add(tripsFragment);
    }

Next, we’ll define the buildFragment() method. It’s job is to initialize each BottomBarFragment to hold the correct Bottom Navigation item title.

private BottomBarFragment buildFragment(String title) {
       BottomBarFragment fragment = new BottomBarFragment();
       Bundle bundle = new Bundle();
       bundle.putString(BottomBarFragment.ARG_TITLE, title);
       fragment.setArguments(bundle);
       return fragment;
   }

We now have a list of fragments that hold 3 BottomBarFragment. Each Fragment here holds its respective Bottom Navigation item title. The fragments in the List are in the same order as the Bottom Navigation items.

2. Inflate Fragment based on position

Lastly, we inflate the correct Fragment of the 3, into our FrameLayout.

Let’s write a generic method that handles the Fragment switching for us.

private void switchFragment(int pos, String tag) {
       getSupportFragmentManager()
               .beginTransaction()
               .replace(R.id.frame_fragmentholder, fragments.get(pos), tag)
               .commit();
   }

There are 2 scenarios to handle:

a. App launch

We need to show a Fragment by default, when the app launches. This would obviously be the very first item in the Bottom Navigation, ‘Calls’ item.

Android Material UI Template 8 in 1 CodeCanyon

Add this line in BottomBarActivity.onCreate().

// Set the 0th Fragment to be displayed by default.
        switchFragment(0, TAG_FRAGMENT_CALLS);

It would be wise to maintain constant tags to uniquely identify each Fragment (Bottom Navigation Item).

private static final String TAG_FRAGMENT_CALLS = "tag_frag_calls";
    private static final String TAG_FRAGMENT_RECENTS = "tag_frag_recents";
    private static final String TAG_FRAGMENT_TRIPS = "tag_frag_trips";
 b. Bottom Navigation item clicks

When a Bottom Navigation item is clicked, the view is changed. In relative terms, we show the relevant BottomBarFragment.

Modify your BottomNavigationView item click listener as follows.

bottomNavigationView.setOnNavigationItemSelectedListener(
               new BottomNavigationView.OnNavigationItemSelectedListener() {
                   @Override
                   public boolean onNavigationItemSelected(@NonNull MenuItem item) {
                       switch (item.getItemId()) {
                           case R.id.action_bottombar_calls:
                               switchFragment(0, TAG_FRAGMENT_CALLS);
                               return true;
                           case R.id.action_bottombar_recents:
                               switchFragment(1, TAG_FRAGMENT_RECENTS);
                               return true;
                           case R.id.action_bottombar_trips:
                               switchFragment(2, TAG_FRAGMENT_TRIPS);
                               return true;
                       }
                       return false;
                   }
               });

Here’s the complete BottomBarActivity.java for your reference.

public class BottomBarActivity extends AppCompatActivity {
    private static final String TAG_FRAGMENT_CALLS = "tag_frag_calls";
    private static final String TAG_FRAGMENT_RECENTS = "tag_frag_recents";
    private static final String TAG_FRAGMENT_TRIPS = "tag_frag_trips";

    private BottomNavigationView bottomNavigationView;
    /**
     * Maintains a list of Fragments for {@link BottomNavigationView}
     */
    private List<BottomBarFragment> fragments = new ArrayList<>(3);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_bottom_bar);

        bottomNavigationView = (BottomNavigationView) findViewById(R.id.bottom_nav);

        bottomNavigationView.setOnNavigationItemSelectedListener(
                new BottomNavigationView.OnNavigationItemSelectedListener() {
                    @Override
                    public boolean onNavigationItemSelected(@NonNull MenuItem item) {
                        switch (item.getItemId()) {
                            case R.id.action_bottombar_calls:
                                switchFragment(0, TAG_FRAGMENT_CALLS);
                                return true;
                            case R.id.action_bottombar_recents:
                                switchFragment(1, TAG_FRAGMENT_RECENTS);
                                return true;
                            case R.id.action_bottombar_trips:
                                switchFragment(2, TAG_FRAGMENT_TRIPS);
                                return true;
                        }
                        return false;
                    }
                });

        buildFragmentsList();

        // Set the 0th Fragment to be displayed by default.
        switchFragment(0, TAG_FRAGMENT_CALLS);

    }

    private void switchFragment(int pos, String tag) {
        getSupportFragmentManager()
                .beginTransaction()
                .replace(R.id.frame_fragmentholder, fragments.get(pos), tag)
                .commit();
    }

    private void buildFragmentsList() {
        BottomBarFragment callsFragment = buildFragment("Calls");
        BottomBarFragment recentsFragment = buildFragment("Recents");
        BottomBarFragment tripsFragment = buildFragment("Trips");

        fragments.add(callsFragment);
        fragments.add(recentsFragment);
        fragments.add(tripsFragment);
    }

    private BottomBarFragment buildFragment(String title) {
        BottomBarFragment fragment = new BottomBarFragment();
        Bundle bundle = new Bundle();
        bundle.putString(BottomBarFragment.ARG_TITLE, title);
        fragment.setArguments(bundle);
        return fragment;
    }
}

Conclusion

Wow, that took longer than expected! Now with everything done, go ahead and run the app.

If your app looks similar to that, give yourselves a pat on the back.

Congratulations! We’ve successfully added Bottom Navigation to our apps.

Source Code:

View Project on GitHub

 

Quick Recap

In this article, we set up a BottomNavigationView and reacted to item clicks. Then we looked into styling options with XML selectors. Finally, we saw how to set up navigation between Fragments using the Bottom Navigation Items.

Now all that’s left is for you to decide what content goes into each Fragment. I am sure you will create something great. Good luck with that!

Is there anything you’d like to add to this article? Let me know in the comments.

If you liked reading this article, share it to your social network.

App developer with an eye for design. Loves to create apps with good UI/ UX that doesn’t annoy people. In his spare time, he likes to draw and paint.
Subscribe to Newsletter
Be the first to get latest updates and exclusive content
straight to your email inbox.
STAY UPDATED
Chill, I hate spam too. You can unsubscribe anytime.

Suleiman

App developer with an eye for design. Loves to create apps with good UI/ UX that doesn't annoy people. In his spare time, he likes to draw and paint.

You may also like...

  • Osas

    I have a type mismatch exception in IntelliJ – “Found BottomBarFragment, required: Fragment”. I compared my code with Yours on GitHub and everything looks the same, what should I do? Any idea?

  • great tutorial

  • xan

    I never understood the difference between BottomNavigationView and Navigation Drawer in terms of UX

    • Initially, the difference wasn’t very clear to me either. Use Bottom Navigation when you have max 4-5 navigation items. Anything more that requires complex navigation, use a Navigation Drawer. I’ve discussed a bit about it here. Might give you a better understanding: http://blog.grafixartist.com/bottom-navigation-bar-android-tutorial/

      • xan

        i read it, so:
        – Navigation Drawer is a main level navigation with much menu item, also has header to put user profile or other things
        – Bottom Navigation is a main level navigation with few menu item, and without header, also has conflict with Actionbar Tabs
        – Actionbar Tabs is a sub level navigation

        SO: Bottom Navigation is useless

      • I like how you put it.

        The Tabs are specifically for, and I quote “to organize content at a high level, for example, to present different sections of a newspaper…”. You can read about its usage here: https://material.io/guidelines/components/tabs.html#tabs-usage

        If you were to display Tabs (for different screens) that are not at all related to one another, then use Bottom Navigation instead.

        But just don’t use both, as it would just confuse people.

  • mendibar

    Can I use activities instead of fragments? I mean when I select an Item it shows an activity which has a viewpager with different fragments, like the “google +” app that also use a bottom navigation bar…

    • Hi,
      You cannot use Activities like that I’m afraid. I guess what you’re talking about is the Collections item in the Bottom Navigation. This could be a Fragment where the ViewPager hosts child Fragments.

      However, be careful when using Tabs and Bottom Navigation together. It might get confusing.

Subscribe to Newsletter
Be the first to get latest updates and exclusive content
straight to your email inbox.
STAY UPDATED
Chill, I hate spam too. You can unsubscribe anytime.
Gradle setup, ProGuard rules, Material Design palette, metrics and much more

FREE Material Design Starter Project

For more details, click on the below link.
GET IT NOW FOR ANDROID STUDIO!
Download FREE
STARTER PROJECT
Material Design Template Project for Android Studio
DOWNLOAD STARTER PROJECT
Udemy Learn Fest - Learn from experts around the world! (Upto 90% off)
SPECIAL COURSE DISCOUNT