Using Bottom Navigation View – Android Design Support Library

This tutorial is now updated for AndroidX!

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.

READ
Easy Bottom Navigation Tutorial with a custom library

The above article includes:

  1. Easy third-party implementation
  2. when to use Bottom Navigation and the difference with Navigation Drawer
  3. transition animations

However, if you want to use the official libraries (which are equally good, if not, better), read on below!

The Design Support Library is so popular, chances are that you’re already using it. Since it now includes BottomNavigationView, it might make little sense to rely on third-party.

Adding Dependencies

Start by adding the relevant support library dependencies.

dependencies {
    ...
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'com.google.android.material:material:1.0.0'
    // Other Dependencies
}

 Adding BottomNavigationView to Layout

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

<com.google.android.material.bottomnavigation.BottomNavigationView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"
        app:itemBackground="?attr/colorPrimary"
        app:itemIconTint="@drawable/selector_bottombar"
        app:itemTextColor="@drawable/selector_bottombar"
        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.

UX DESIGN TIP
Remember to keep your non-active tab items (icon+text) visible at all times so people know what they are, even when its not active.

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 = 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

Going by our XML, our Bottom Nav’s background is colored. We want to light up our active item with 100% white and want the inactive ones dim. So let’s say the inactive tab items are at 40% white. Here is the XML selectors for the same.

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_40"/>
</selector>

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

...  
    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/bottom_nav"
      ...
        app:itemIconTint="@drawable/selector_bottombar"
        app:itemTextColor="@drawable/selector_bottombar"
        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 =  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"/>     
  <com.google.android.material.bottomnavigation.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.

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:

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.

Suleiman

Product Designer who occasionally writes code.

You may also like...

17 Responses

  1. Rushdi says:

    Hi sir, your explanation is very prefect and clear, but I have and Extra question. suppose we have a bottom navigation view which consists of 4 main, the fourth tab consists of (login and user account Fragments) and we want this login fragment to be replaced with the userAccount fragment once user has logged in successfully.

    I hope I will get your help because I have searched everywhere and never got the answer for that.

    Thanks

    • Suleiman says:

      Hi Rushdi,
      If your Bottom Navigation bar’s icon would also change, then I would think about it like this. Have two bottom bars. One for non-logged in and one for after login. Based on your logic, I would swap these two bars. Of course, the 4th item for your after login bottom bar would load the useraccount fragment onclick.
      In other words, you’d have 2 replicates of your bottom nav XML. The only difference is, the 4th item onclick would load a different Fragment.
      Hope this answers your question.

  2. Amanda says:

    Hi, Do you know any way to put a top border only in the item selectd?

  3. K. Arslan says:

    hi bro, thx for the great helps.. But what about if we want to use navigation drawer with bottom app bar (or bottom navigation view) at the same time. Couldn’t find a solution for it, maybe you can recommend something? Thank you a lot again

  4. Domenico Guarino says:

    PERFECT, thank you very much

  5. Arun says:

    hi how to hide bottom navigation when we scroll

  6. Wisnu Andrian says:

    Hi bro i need add 1 more tab icon in my buttom navigation view , but if i add 1 item in buttombar_menu . the order on xml messy . can you give me solution for this ? https://uploads.disquscdn.com/images/3d7dcc1e87d894a91761e24fa06b544d3a323f8db6dcf720871acdd65c1878ef.png

  7. Osas says:

    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?

  8. xan says:

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

    • Suleiman19 says:

      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: https://blog.iamsuleiman.com/bottom-navigation-bar-android-tutorial/

      • xan says:

        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

      • Suleiman19 says:

        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.

  9. mendibar says:

    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…

    • Suleiman19 says:

      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.

Leave a Reply

Your email address will not be published. Required fields are marked *