104

I have added BottomNavigationView in my application like.

main.xml

<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="@color/white"
        app:itemTextColor="@color/white"
        app:menu="@menu/bottom_navigation_main" />

bottom_navigation_main.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/action_favorites"
        android:enabled="true"
        android:icon="@drawable/ic_favorite_white_24dp"
        android:title="@string/text_favorites"
        app:showAsAction="ifRoom" />
    <item
        android:id="@+id/action_schedules"
        android:enabled="true"
        android:icon="@drawable/ic_access_time_white_24dp"
        android:title="@string/text_schedules"
        app:showAsAction="ifRoom" />
    <item
        android:id="@+id/action_music"
        android:enabled="true"
        android:icon="@drawable/ic_audiotrack_white_24dp"
        android:title="@string/text_music"
        app:showAsAction="ifRoom" />
</menu>

MainActivity click

bottomNavigationView.setOnNavigationItemSelectedListener(
        new BottomNavigationView.OnNavigationItemSelectedListener() {
            @Override
            public boolean onNavigationItemSelected(@NonNull MenuItem item) {
                switch (item.getItemId()) {
                    case R.id.action_favorites:
                        //need change icon of favotites here.
                    case R.id.action_schedules:

                    case R.id.action_music:

                }
                return true;
            }
        });

I want to change the icon of the bottom navigation of selected position. How can we achieve this feature when user click one item?

(if user clicked one item then the icon change to another one)

PEHLAJ
  • 9,980
  • 9
  • 41
  • 53
Adarsh
  • 2,219
  • 2
  • 23
  • 37
  • 1
    Anyone having selectors in his menu and want to show the selectors colors instead of default bottom nav colors check this answer https://stackoverflow.com/a/44516194/6039240 – Amr Jan 13 '22 at 07:03

11 Answers11

180

You can simply create drawable selector in drawable folder and image can be change according to the state of the widget used in view

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/calender_green" android:state_checked="true"/>
    <item android:drawable="@drawable/calender_black" android:state_checked="false"/>
</selector>
Nik
  • 9,063
  • 7
  • 66
  • 81
kuljeet singh
  • 2,792
  • 2
  • 12
  • 15
  • 28
    This works better than the programmatic method. The state to specify is actually `android:state_checked` not `android:state_selected` – Yuntao Apr 27 '17 at 21:19
  • Where to apply this? – Pinkesh Darji Mar 07 '18 at 09:35
  • 1
    You should apply here: `` – sfmirtalebi May 11 '18 at 18:10
  • 2
    its not working in kitkat android version. app getting crash. – Hitesh Sarsava Jun 09 '18 at 18:01
  • When you do this, the logo is changing but the selection color is being inherited from app theme color. do you know how to avoid that – ASN Jun 11 '18 at 03:10
  • 1
    @ASN remove the tint from the bottom navigation xml code to restore the original color of the icons – Abhinav Upadhyay Oct 27 '18 at 14:13
  • @HiteshSarsava you need to use in your activity the next code: `static { AppCompatDelegate.setCompatVectorFromResourcesEnabled(true); }` Please, check [this answer](https://stackoverflow.com/a/40523623/4512868) – Tomas Nov 06 '18 at 07:23
  • How can you do this with two navigation items? If i want item one to change to an image and item 2 to change to the other? – A. Petrizza Nov 25 '18 at 08:24
  • 9
    @AbhinavUpadhyay removing itemIconTint from xml still doesn't work. bottomNavigationView.setItemIconTintList(null) is the solution. Do you know equivalent in xml? – VipiN Negi Mar 05 '19 at 10:51
  • @VipiNNegi there are multiple tints there, I think there is a background tint, icon tint and more. So try removing them all and then see. Its been sometime since I resolved this problem – Abhinav Upadhyay Mar 05 '19 at 13:44
  • How can add selector for every item of the bottom navigation view ? – pandey_shubham Mar 18 '21 at 08:41
117

I found this is better approach to use selector drawable:

At first create an xml file in your drawable folder. For example, xml file name is child_selector.xml at drawable folder.

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

Simply add child_selector in menu item of your bottom_navigation_main.xml:

Like: android:icon="@drawable/child_selector"

Example:

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

<item
    android:id="@+id/navigation_child"
    android:icon="@drawable/child_selector"
    android:title="@string/title_child" />

</menu>

And must add following line in your activity-

bottomNavigationView.setItemIconTintList(null);
starball
  • 20,030
  • 7
  • 43
  • 238
Saiful Islam Sajib
  • 2,243
  • 1
  • 12
  • 17
102

If above solutions are not working for you to change selected item icon then add below line to your code:

bottomNavigationView.setItemIconTintList(null);

This will disable tint effect of selected item icon.

I had the same problem. I have added selector drawable for changing icon of BottomNavigationView item when its checked/selected.

Kishan Solanki
  • 13,761
  • 4
  • 85
  • 82
47

You need to reset the icon onclick, and then on the switch case you need to set only the one you need to change, so only when selected the icon change.

Menu menu = bottomNavigationView.getMenu();
menu.findItem(R.id.action_favorites).setIcon(favDrawable);

switch (item.getItemId()) {
                case R.id.action_favorites:
                     item.setIcon(favDrawableSelected);
                case R.id.action_schedules:
                case R.id.action_music:
            }
  • 1
    I think it would be helpful to explicitly add that piece of code declaring 'item' as well. MenuItem item = menu.findItem(R.id.action_favorites); – Akah Aug 02 '17 at 13:43
  • 1
    i'll try this code it's work but when i click other icon then it's not set default icon like fill the icon or not fill icon – Ali Feb 13 '18 at 07:32
  • this works but how to reset the icon back to the original one when another item is clicked – Eswar Jul 27 '18 at 10:42
  • 1
    in my case i was just trying to change different tint color for different button, got this by, bottomNavigationView.itemIconTintList = ColorStateList.valueOf(ContextCompat.getColor(this, iconColor)) – iamsujan Aug 01 '18 at 16:48
  • 1
    This works, but could be a good bit extra work. Check answers below for cleaner solutions. – Michael Oct 18 '18 at 19:19
  • This will actually work, the only problem would be if you want the icon to change when it's selected and change back when it's not, since the item passed by the switch is just the tapped one you will have no reference to the others, so you'll not be able to restore the state if you deselect it for example. Check Saiful Islam Sajib's answer down below for the whole drill on how to implement a selector drawable, that would be the best and cleanest approach in my opinion. – Manuel Mariano Silva Dec 11 '20 at 13:07
35

Okay I wanted to understand how to have each item have their own image, and with some confusion in the comments on where it should go, I wanted to type up this answer.

First create your menu and its items. Your selector will go inside those items in the ICON value. Here we have 2 selectors, each made for its menu item.

item
    android:id="@+id/navigation_home"
    android:icon="@drawable/navigation_home_selector"
    android:title="@string/title_home" />
item
    android:id="@+id/navigation_profile"
    android:icon="@drawable/navigation_profile_selector"
    android:title="@string/title_profile" />

Now here is your selector file that will be housed in your drawable folder.

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

Final step was provided by @ KishanSolanki124

Add this line of code to your BottomNavigationView.

BottomNavigationView.setItemIconTintList(null);

There you have it. All works like a charm.

A. Petrizza
  • 3,202
  • 2
  • 15
  • 24
  • 1
    how to change icon text color?? – Ashik Azeez Dec 13 '18 at 06:23
  • I believe you can set this on the navigationListener. `BottomNavigationView.SetTextColor` – A. Petrizza Dec 19 '18 at 06:58
  • The critical piece of missing information for me in this answer (and several others) is that the selector xml must be placed in a file in the drawable folder called navigation_home_selector.xml; that name makes the link from the android:icon=@drawable/navigation_home_selector to the smart drawable object work. – JohnT Jul 28 '20 at 17:36
  • @JohnT that is implied by the actual value inside of the ICON section. It is telling you that the file is inside drawable with that name. – A. Petrizza Sep 10 '20 at 02:51
14

The above answer from ajay singh https://stackoverflow.com/a/57248961/9793057 helped me out, as well as employing answers from above.

The following code within res->drawable folder (selector_stock_bottom_nav_view.xml)

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:color="@color/button_and_tab_color" android:state_checked="true" />
    <item android:color="@android:color/darker_gray" android:state_checked="false" />
</selector>

These are the attributes in my bottom navigation view

<com.google.android.material.bottomnavigation.BottomNavigationView

        app:itemIconTint="@drawable/selector_stock_bottom_nav_view" //To change icon color
        app:itemTextColor="@drawable/selector_stock_bottom_nav_view" //To change text color
        app:itemTextAppearanceActive="@style/stockBottomNavigationView.Active" //To change size of text during active state
        app:itemTextAppearanceInactive="@style/stockBottomNavigationView.InActive"
        app:menu="@menu/bottom_navigation_menu"
        app:labelVisibilityMode="labeled"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:layout_gravity="bottom"
        app:selectedBackgroundVisible="false"
        android:id="@+id/stock_bottom_navigation"/>

I DID-NOT use "BottomNavigationView.setItemIconTintList(null)" anywhere in my code.

Now here comes the most important piece of code, make sure to return "TRUE" in bottom navigation view's listener, i.e,

private BottomNavigationView.OnNavigationItemSelectedListener stockBottomNavListener = new BottomNavigationView.OnNavigationItemSelectedListener() {
        @Override
        public boolean onNavigationItemSelected(@NonNull MenuItem item) {

            return true;

        }
    };

Bonus: To change size of text active/inactive state Place the following code in styles.xml file

    <style name="stockBottomNavigationView.InActive" parent="@style/TextAppearance.AppCompat.Caption">
        <item name="android:textSize">7sp</item>
    </style>

    <style name="stockBottomNavigationView.Active" parent="@style/TextAppearance.AppCompat.Caption">
        <item name="android:textSize">8sp</item>
    </style>

The above answer is a compilation of answers from various answers in stackoverflow related to bottom navigation views, icon & text color/size change.

Subind Suresh
  • 189
  • 2
  • 6
2

Thanks for the selector method, that works for me (api v26)

For those who wondering how to set it back to origin unselected icon programmatically, consider add this to your OnNavigationItemSelectedListener before your switch(Java) or when(Kotlin) :

private val mOnNavigationItemSelectedListener = BottomNavigationView.OnNavigationItemSelectedListener { item ->
    navigation.menu.getItem(0).setIcon(R.drawable.ic_tab_home)
    navigation.menu.getItem(1).setIcon(R.drawable.ic_tab_account)
    navigation.menu.getItem(2).setIcon(R.drawable.ic_tab_trading)
    navigation.menu.getItem(3).setIcon(R.drawable.ic_tab_wallet)
    when (item.itemId) {
        R.id.navigation_home -> {
            message.setText(R.string.title_home)
            item.setIcon(R.drawable.ic_tab_home_active)
            return@OnNavigationItemSelectedListener true
        }
        R.id.navigation_account -> {
            message.setText(R.string.title_account)
            item.setIcon(R.drawable.ic_tab_account_active)
            return@OnNavigationItemSelectedListener true
        }
        R.id.navigation_trading -> {
            message.setText(R.string.title_trading)
            item.setIcon(R.drawable.ic_tab_trading_active)
            return@OnNavigationItemSelectedListener true
        }
        R.id.navigation_wallet-> {
            message.setText(R.string.title_wallet)
            item.setIcon(R.drawable.ic_tab_wallet_active)
            return@OnNavigationItemSelectedListener true
        }
    }
    false
}
Wesely
  • 1,425
  • 14
  • 23
1

Found the answer. we can use

item.setIcon(R.drawable.icon_name) 

to change the icon .. will try to imporve answer

 bottomNavigationView.setOnNavigationItemSelectedListener(
            new BottomNavigationView.OnNavigationItemSelectedListener() {
                @Override
                public boolean onNavigationItemSelected(@NonNull MenuItem item) {
                    switch (item.getItemId()) {
                        case R.id.action_favorites:
                            //change the icon
                         item.setIcon(R.drawable.icon_name);
                        case R.id.action_schedules:

                        case R.id.action_music:

                    }
                    return true;
                }
            });
Adarsh
  • 2,219
  • 2
  • 23
  • 37
  • 2
    this works but how to reset the icon back to the original one when another item is clicked. – Eswar Jul 27 '18 at 10:37
  • 1
    @Eswar look at my answer above this one. Use a selector and it can use 2 different images entirely or a color changed image(What my app is doing) – A. Petrizza Dec 19 '18 at 07:00
1

You can dynamically set your icon using this method.

R.id.navigation_menu is your item id in your R.menu.menu_bottom_navigation.

val menuItem = bottomNavigationView.menu.findItem(R.id.navigation_menu)
menuItem.setIcon(R.drawable.ic_icon)
Morgan Koh
  • 2,297
  • 24
  • 24
-1

On Material 3

You need to create a style and put your colors on:

 <style name="BottomNavigationView">
        <item name="colorSecondaryContainer">@color/background_dark</item>
        <item name="colorSurface">?attr/colorPrimaryVariant</item>
        <!--  Icon color Active  -->
        <item name="colorOnSecondaryContainer">@color/yellow</item>
        <!--  Text Color Active -->
        <item name="colorOnSurface">@color/yellow</item>
</style>

To see inactive colors, check the documentation.

-3

In the Latest material Design library default behavior of BottomNavigation is provided where you don't need to provide property itemIconTint it will manage it automatically.

<com.google.android.material.bottomnavigation.BottomNavigationView
    android:id="@+id/bottomNavigationView"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:layout_marginStart="0dp"
    android:layout_marginEnd="0dp"
    android:layout_alignParentBottom="true"
    android:background="?android:attr/windowBackground"
    app:itemBackground="@color/white"
    app:itemTextColor="@color/textBlue"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:menu="@menu/bottom_navigation"
    app:labelVisibilityMode="labeled"
    app:itemTextAppearanceActive="@color/colorPrimary"
    />
ice spirit
  • 1,425
  • 3
  • 16
  • 32