Background color change in BottomNavigationView

47.1k views Asked by At

I have implemented BottomNavigationView which is available from the new support library 25.0.0. Here is my code for that

<android.support.design.widget.BottomNavigationView
    android:id="@+id/bottom_navigation"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    app:itemBackground="@color/colorPrimary"
    app:itemIconTint="@drawable/text"
    app:itemTextColor="@drawable/text"
    app:menu="@menu/bottom_navigation_main" />

And text.xml drawable

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:color="@android:color/white" android:state_enabled="true" />
    <item android:color="@color/colorPrimaryDark" android:state_enabled="false" />
</selector>

With this code I am able to change text color when menu item is clicked, but when I apply same thing to app:itemBackground it is showing error <item> tag requires a 'drawable' attribute or child tag defining a drawable.

This is what I have tried for app:itemBackground

app:itemBackground="@drawable/text"

So my question is how can I change the background color of the selected menu item?

5

There are 5 answers

2
Ravi On BEST ANSWER

found an answer from this medium post

  1. We need to use android:state_checked instead of android:state_enabled
  2. within onNavigationItemSelected you need to use return true instead of return false.

and to set background, we cannot use android:color in <item>, we need to use android:drawable

So here how it looks xml file when you are setting it for app:itemTextColor and app:itemIconTint

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:color="@color/colorPrimaryDark" android:state_checked="true" />
    <item android:color="@android:color/white" android:state_checked="false" />
</selector>

and to set app:itemBackground selector

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/banner_white" android:state_checked="true"/>
    <item android:drawable="@drawable/banner_green" android:state_checked="false"/>
</selector>

Here banner_white and banner_green are pngs.

2
Apoorv Mehrotra On

Try this it is a sample code of navigation item select listener. hope it helps you.

 @Override
  public boolean onNavigationItemSelected(final MenuItem menuItem) {
    // update highlighted item in the navigation menu
    menuItem.setChecked(true);
    mNavItemId = menuItem.getItemId();

    // allow some time after closing the drawer before performing real navigation
    // so the user can see what is happening
    mDrawerLayout.closeDrawer(GravityCompat.START);
    mDrawerActionHandler.postDelayed(new Runnable() {
      @Override
      public void run() {
        navigate(menuItem.getItemId());
      }
    }, DRAWER_CLOSE_DELAY_MS);
    return true;
  }

Alternative solution:

Make a drawable file highlight_color.xml with following contents :

<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
     <solid android:color="YOUR HIGHLIGHT COLOR"/>
</shape>

Make another drawable file nav_item_drawable.xml with following contents:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:drawable="@drawable/highlight_color" android:state_checked="true"/>
</selector>

Finally add app:itemBackground tag in the NavView :

<android.support.design.widget.NavigationView
android:id="@+id/activity_main_navigationview"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:headerLayout="@layout/drawer_header"
app:itemIconTint="@color/black"
app:itemTextColor="@color/primary_text"
app:itemBackground="@drawable/nav_item_drawable"
app:menu="@menu/menu_drawer">

here the highlight_color.xml file defines a solid color drawable for the background. Later this color drawable is assigned to nav_item_drawable.xml selector.

Try this one.

3
UnluckyNinja On

I encountered a similar problem to the OP's, but a little different. If you put sth like@color/color_selector into the BottomNavigationView's app:itemBackground="___". It will cause the view to hide in design panel, and the app to crush when launching. Though it works fine if your just set it to a constant color like @color/black.

For a more in-depth explanation, I dug into android api reference. Now I think I have found the answer that can reasonably resolve this problem. (May not accurate.)

The problem is, what you provide are NOT EXACTLY what they asked for.

app:itemIconTint and app:itemTextColor ask for a hex color, while app:itemBackground asks for a literally Drawable. The <color> elements we write in colors.xml are ColorDrawable. It's derived from Drawable so it can feed all three attributes.

However, when you change it to use a selector, things become different. Both hex color and drawable have a corresponding selector. A selector acts like the resource you put in, but the outcome is not the original one. It's more like a single-purpose wrapper. You can't feed a hex color to an attribute who requires a Drawable.

The color selector is actually a ColorStateList, provides a hex color, resides in res/color. You can use only the attribute android:color in this file. it will prompt an error if you write android:drawable.
The drawable selector is StateListDrawable, provides Drawable, resides in res/drawable. You should write android:drawable here, but there is no error if you write android:color.

However android:color only provides a hex color that can't be recognized as a Drawable, while app:itemBackground requires a Drawable, so the app is doomed. (Direct cause)

Both attribute (android:color and android:drawable) accept a ColorDrawable, here it works just like when you set a constant color.

The solution (and the practice) is:

  • Use (and only) android:drawable in a res/drawable/drawable_selector.xml. Example:

    <?xml version="1.0" encoding="utf-8"?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:drawable="@color/colorAccent" android:state_checked="true" />
        <item android:drawable="@color/colorAccentDark" />
    </selector>
    
  • Use res/color/color_selector.xml when it needs a hex color (to avoid confusing). Example:

    <?xml version="1.0" encoding="utf-8"?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:color="@android:color/white" android:state_checked="true"/>
        <item android:color="@color/colorPrimary" />
    </selector>
    
  • Provide app:itemBackground with drawable. Example:

    <android.support.design.widget.BottomNavigationView
        ...
        app:itemBackground="@drawable/drawable_selector"
        app:itemIconTint="@color/color_selector"
        app:itemTextColor="@color/color_selector"
        ... />
    

(Worth noting that if you are using Android Studio, its auto-completion feature will tell you what attributes are legal and available, and it doesn't suggest you android:color in a selector under res/drawable!)

3
Yakov Weber On

first create xml bottom_navigation_items with

<ripple xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="?android:colorControlHighlight">
    <item>
        <selector>
            <item
                android:drawable="@color/primary_bottom_select"
                android:state_checked="true" />
            <item
                android:drawable="@color/bottom_navigation"
                android:state_checked="false" />
        </selector>
    </item>
</ripple>

second: add app:itemBackground="@drawable/bottom_navigation_items"

0
Huy Nguyen On

An easy way worked for me:

<BottomNavigationView
...
android:theme="@style/CustomTheme"/>
<style name="CustomTheme">
   <item name="android:background">@color/colorPrimary</item>
</style>