42

I used Android Studio to implement the Navigation Drawer and I can't get the blue colour that is used to show which section we're currently in to change.

I've tried numerous things, I'm currently using a listSelector which looks like:

<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:state_activated="true" android:drawable="@color/selected" />
    <item android:state_pressed="true" android:drawable="@color/highlight" />


</selector>

I've also tried state_checked. state_pressed works in this situation but the currently selected item is still blue.

EDIT: I've been examining this more and when the adapter is created the context that is passed is getActionBar().getThemedContext() so I'm thinking if I can find the right attribute to assign to my actionbar style I can change it from there. I've tried a few different attributes with no luck. Does anyone know the exact attribute?

I've also realised if I put

<item name="android:activatedBackgroundIndicator">@drawable/nav_listview_selector</item>

in the main part of my theme and change getActionBar().getThemedContext() for getActivity.getBaseContext then I can change the color but I don't think this is the correct way. I think the themed context should be used. So if anyone knows where the activatedBackgroundIndicator could be put so that it would be used in getActionBar.getThemedContext()

EDIT2:

So the text view used for the listview is one within the SDK it looks like this:

<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@android:id/text1"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:textAppearance="?android:attr/textAppearanceListItemSmall"
    android:gravity="center_vertical"
    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
    android:background="?android:attr/activatedBackgroundIndicator"
    android:minHeight="?android:attr/listPreferredItemHeightSmall"
/>

So I tried modifying the "?android:attr/activatedBackgroundIndicator" at the theme level but it has no effect for checked/selected/activated but it does for pressed. Does anyone know why this is? And how I can change it?

RyanJohnstone
  • 802
  • 1
  • 9
  • 21
  • I ended up using also `state_selected` (in addition to your `checked` and `pressed`) + `ListView.setItemChecked`. Took me ages so I may have a state too many defined – velis Mar 14 '14 at 07:45
  • I think I've already tried that at some point. And the setItemChecked is used as it's part of Android Studios auto implementation. – RyanJohnstone Mar 14 '14 at 08:04
  • Correct, when I used the default implementation of the navigation drawer via Android Studio, the currently active fragment's title on the navigation drawer is highlighted blue and I would like to change that blue to be a color I use for my app and also make the font bold but only for the selected item. Maybe its the xml file I am using for my background. Currently its applying the color change and the bold text to each item in the navigation drawer. – Chris D Apr 17 '14 at 11:17

13 Answers13

52

To solve this problem:

1- You don't need android:listSelector under your ListView.

2- Open (or Create) styles.xml under (res/values).

<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <!-- Customize your theme here. -->
    <item name="android:activatedBackgroundIndicator">@drawable/drawer_list_selector</item>
</style>

3- Under res/drawable folder create drawer_list_selector.xml file

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true" android:drawable="@drawable/light_gray_color" />
    <item android:state_activated="true" android:drawable="@drawable/red_color" />
    <item android:drawable="@android:color/transparent" />
</selector>

4- Under res/drawable create red_color.xml / light_gray_color.xml (or any other name) and add your desired Hex color:

<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="#C8FF0000"/>
</shape>

5- Open your project AndroidManifest.xml and add android:theme tag (if not exist)

<application
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >

Reference / Credit: Changing Navigation Drawer Selected Item Color from default blue

Community
  • 1
  • 1
Ashraf Alshahawy
  • 1,139
  • 1
  • 14
  • 38
  • 3
    This is it. This is the answer you're looking for. All other answers on this site for this problem are roundabout ways of doing it. This is the easiest to implement and the one that gets the best results. – Muhammad Abdul-Rahim Oct 06 '15 at 17:44
  • 5
    This is not working for me. The list item corresponding to the current activity is not painted in its respective colour(which I guess is red in your code). – Flame of udun Oct 23 '15 at 03:23
  • 5
    Yes, It worked for me. Only after setting itemBackground="@drawable/drawer_list_selector" in NavigationDrawer instead of calling it on AppTheme. Also using item.setCheckable(true); and item.setChecked(true); inside onNavigationItemSelected(MenuItem item); – Pratik Saluja Nov 05 '16 at 05:30
  • I had to use this on: `android:selectableItemBackground` instead of `android:activatedBackgroundIndicator` for this to work on my recyclerview and drawer items. Everything else in the answer remained unchanged. I hope this helps. – Aspiring Dev Apr 07 '17 at 15:54
  • It seems I spoke to soon. Neither of these solutions work for 4.2 devices :( – Aspiring Dev Apr 07 '17 at 18:05
  • 1
    doesnt work on Android O, background remains grey :( – kashlo Oct 06 '18 at 14:31
13

To change the "Navigation Drawer item background colour for selected item" you could do it with the attribut:

colorControlHighlight

In your "styles.xml" it could look like this:

<style name="YourStyleNameFor.NavigationDrawer" parent="ThemeOverlay.AppCompat.Light">
    <item name="colorControlHighlight">@color/your_highlight_color</item>
</style>

Don't forget to apply your Style in the tag:

android.support.design.widget.NavigationView

For example in your activity_main.xml it could look like this:

<android.support.design.widget.NavigationView
    android:id="@+id/nav_view"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_gravity="start"
    android:fitsSystemWindows="true"
    app:headerLayout="@layout/navigationdrawer_header"

    <!-- the following line referes to your style  -->
    app:theme="@style/YourThemeNameFor.NavigationDrawer"

    <!-- the following two lines are maybe also interesting for you -->
    app:itemIconTint="@color/gray3"
    app:itemTextColor="@color/gray3"

    app:menu="@menu/navigationdrawer_main" />
user3570407
  • 169
  • 1
  • 5
10

This is working for me:

  1. First define a drawable item_bg.xml as:

    <?xml version="1.0" encoding="utf-8"?>
        <selector xmlns:android="http://schemas.android.com/apk/res/android">
            <item android:state_checked="true" android:drawable="@drawable/nav_menu_bg" />
        </selector>
    
  2. Then use this drawable in navigation_main_layout.xml as:

    <android.support.design.widget.NavigationView
        android:id="@+id/nav_view"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        app:itemBackground="@drawable/item_bg"
        android:fitsSystemWindows="true"
        app:headerLayout="@layout/nav_header_navigation"
        app:menu="@menu/navigation_main_layout_drawer" />
    
Vishal Yadav
  • 3,642
  • 3
  • 25
  • 42
Mithun Biswas
  • 101
  • 1
  • 3
6

here is how i have done and it is working, the brief concept is maintain the position of selected item in adapter and call notifyDataSetChanged on calling notifyDatasetChanged the getView method is called again and in get view check the position on the selected position change the background view. Here is the code :

Adapter of NavigationDrawer List View

public class MenuAdapter extends BaseAdapter {

private static final int TYPE_HEADER = 0;
private static final int TYPE_ITEM = 1;
private Context mContext;
private String name;
private int profile;
private int mIcons[];
private int selectedPosition = 0;
private String mNavTitles[];
private LayoutInflater mInflater;

public MenuAdapter(String titles[], int icon[], String Name, int profile) {
    mNavTitles = titles;
    mIcons = icon;
    name = Name;
    this.profile = profile;
}

public MenuAdapter(String Titles[], int Icons[], Context mContext) {
    mNavTitles = Titles;
    mIcons = Icons;
    this.mContext = mContext;
    mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}

@Override
public int getCount() {
    return mNavTitles.length;
}

@Override
public Object getItem(int position) {
    return position;
}

@Override
public long getItemId(int position) {
    return position;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {

    convertView = mInflater.inflate(R.layout.item_row, parent, false);

    TextView textView = (TextView) convertView.findViewById(R.id.rowText);
    ImageView imageView = (ImageView) convertView.findViewById(R.id.rowIcon);
    final LinearLayout layout = (LinearLayout) convertView.findViewById(R.id.outerLayout);

    imageView.setImageResource(mIcons[position]);
    textView.setText(mNavTitles[position]);

    if (position == selectedPosition)
        layout.setBackgroundColor(mContext.getResources().getColor(R.color.app_bg));
    else  
      layout.setBackgroundColor(mContext.getResources().getColor(R.color.normal_bg));

    return convertView;
}

public void setSelectedPosition(int position) {

    this.selectedPosition = position;

}


}

in your activity do this

 private class DrawerItemClickListener implements ListView.OnItemClickListener {
    @Override
    public void onItemClick(AdapterView parent, View view, int position, long id) { 
        mMenuAdapter.setSelectedPosition(position - 1);
        mMenuAdapter.notifyDataSetChanged();
    }
}

if anyone still face any difficulty, feel free to ask.

Syed Raza Mehdi
  • 4,067
  • 1
  • 31
  • 47
  • 2
    @ayz4sci: Please do not fiddle around with the code of this answer. If you want to propose an improvement to the solution then either leave a comment for the answerer (so that they can improve it) or provide your own answer (only if reasonable, i.e., it provides fundamental improvement). – honk Sep 16 '15 at 12:27
  • honk you are right, @ayz4sci and else part is required as if we are reusing the view in adapter and we don't right else part then multiple option will get highlighted. Thanks a lot for your effort though. – Syed Raza Mehdi Sep 16 '15 at 12:35
  • At the time I wrote the first comment, @ayz4sci had proposed yet another edit, where they changed the line with the `normal_bg` once again to use a `transparent` color. I therefore found the suggestions too experimental. I think it's better if you apply the changes after they have been discussed with you. – honk Sep 16 '15 at 12:49
5

I have implement drawer menu with custom adapter class. May be it will help someone Drawer List

<ListView
    android:id="@+id/listview_drawer"
    android:layout_width="260dp"
    android:layout_height="match_parent"
    android:layout_gravity="start"
    android:background="@color/menu_item_color"
    android:choiceMode="singleChoice"
    android:divider="@android:color/transparent"
    android:dividerHeight="0dp"
    android:fadingEdge="none"
    />

drawer_list_item.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content" 
android:background="@drawable/menu_selector"
>

<ImageView
    android:id="@+id/imgIcon"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerVertical="true"
    android:layout_marginLeft="12dp"
    android:layout_marginRight="12dp"
    android:src="@drawable/ic_menu_home" />

<TextView
    android:id="@+id/lblName"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_centerVertical="true"
    android:gravity="center_vertical"
    android:layout_toRightOf="@+id/imgIcon"
    android:minHeight="48dp"
    android:textColor="@color/menu_txt_color" />

menu_selector.xml

<selector xmlns:android="http://schemas.android.com/apk/res/android" android:exitFadeDuration="@android:integer/config_mediumAnimTime">
<!-- selected -->
<item android:drawable="@color/menu_item_active_color" android:state_focused="true" android:state_pressed="false"/>
<item android:drawable="@color/menu_item_active_color" android:state_pressed="true"/>
<item android:drawable="@color/menu_item_active_color" android:state_activated="true"/>
<item android:drawable="@color/menu_item_active_color" android:state_checked="true"/>
<item android:drawable="@color/menu_item_active_color" android:state_selected="true"/>

<item android:drawable="@color/menu_item_color" android:state_activated="false"/>

Add this on item click listner of listview yourlistview.setItemChecked(position, true);

Bhavin Chauhan
  • 1,950
  • 1
  • 26
  • 47
2
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
   <item android:drawable="@color/list_item_back_pressed" android:state_pressed="true" />
    <item  android:state_activated="true"><color android:color="@color/primary_blue"/></item>
   <item android:drawable="@color/list_item_back_normal"/>

</selector>
Query
  • 625
  • 1
  • 7
  • 22
0

In addition to providing a custom selector drawable for the listSelector, you should also set the background resource of the list item to a similar selector drawable that has different drawables for the different states.

stan0
  • 11,549
  • 6
  • 42
  • 59
  • I don't quite understand. Wouldn't they be the exact same selector? I tried using the same selector as the background and removing the listview selector. I don't understand why the pressed item works but not selected, activated or checked. – RyanJohnstone Mar 13 '14 at 11:43
  • Use it for both of them at the same time - listSelector and item's background. I don't understand that either... and can't explain why, but it worked several times. – stan0 Mar 13 '14 at 11:45
  • This still doesn't work and using the selector for the background means the whole nav draw changes colour and not just the item that is being interacted with. – RyanJohnstone Mar 13 '14 at 11:53
  • Can you check out the edit I made and see if you have any insights? Thanks – RyanJohnstone Mar 14 '14 at 06:35
0

I usually use my custom adapter that has an int selection field, and a setSelection(int) function. And in the getView function I set the background of the view according to position == selection.

Ripityom
  • 426
  • 1
  • 5
  • 12
  • 1
    I feel like this should work with the auto implementation that Android Studio does. And it does to an extent. The selection is shown correctly it's just in the default blue, and nothing I have tried can change that. – RyanJohnstone Mar 14 '14 at 09:23
  • I usually use other indication than background, for example some kind of extra view in the selected row, that's why I do it in the adapter – Ripityom Mar 14 '14 at 09:45
0

Still not sure why it is that it doesn't work. But the way I found around it is to use my own simple_list_item_activated layout to be passed to the ArrayAdapter which was basically the same except for setting the text colour to white. I then replaced getActionBar().getThemedContext() with getActivity().getBaseContext() and it now has an effect.

This may not be the correct way and may have repercussions in the future, but for now I have it working the way I want it to.

RyanJohnstone
  • 802
  • 1
  • 9
  • 21
  • I tried doing the same thing but it applies the changes to all the items in my listview not just the selected items. any ideas where I might be missing something. I created a copy of the simple_list_item_activated and changed android:background to my drawable file and also added android:textStyle="bold". The changes get applied but to each item in the navigation drawer and I'm totally lost on how and why this is doing it this way. – Chris D Apr 17 '14 at 03:20
  • If i understand you correctly, you only want bold and such to be applied to the selected item? In this case i think you would be able to provide a drawable to the item selected value in your selector, which defines the attributes you want the selected item to take? – RyanJohnstone Apr 17 '14 at 09:36
  • Where do you call `getActivity().getBaseContext()`? Could you provide some code? – hgoebl Jan 09 '16 at 08:36
0

I know its too late but I have solved this issue in my app.

Pls dont think it is silly, just simply change the position of "state_pressed" to top.

<item android:drawable="@drawable/list_item_bg_pressed" android:state_pressed="true"/>
<item android:drawable="@drawable/list_item_bg_normal" android:state_activated="false"/>
<item android:drawable="@drawable/list_item_bg_selected" android:state_activated="true"/>
0

In Future if anyone comes here using, Navigation Drawer Activity (provided by Studio in Activity Prompt window)

The answer is -

Use this before OnCreate() in MainActivity

    int[][] state = new int[][] {
            new int[] {android.R.attr.state_checked}, // checked
            new int[] {-android.R.attr.state_checked}
    };

    int[] color = new int[] {
            Color.rgb(255,46,84),
            (Color.BLACK)
    };

    ColorStateList csl = new ColorStateList(state, color);

    int[][] state2 = new int[][] {
            new int[] {android.R.attr.state_checked}, // checked
            new int[] {-android.R.attr.state_checked}
    };

    int[] color2 = new int[] {
            Color.rgb(255,46,84),
            (Color.GRAY)
    };

ColorStateList csl2 = new ColorStateList(state2, color2);

and use this in onNavigationItemSelected() in MainActivity (you dont need to Write this function if you use Navigation Drawer activity, it will be added in MainActivity).

 NavigationView nav = (NavigationView) findViewById(R.id.nav_view);
    nav.setItemTextColor(csl);
    nav.setItemIconTintList(csl2);
    nav.setItemBackgroundResource(R.color.white);

Tip - add this code before If else Condition in onNavigationItemSelected()

Chirag Joshi
  • 409
  • 1
  • 4
  • 13
0

This worked for me : implemented menu drawer not by populating the navigation view with list, but with menu items.

created a drawable like this :

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

and in onCreate method , set the id of the menu item which corresponds to selected activity as checked. and implement the drawable selector file to your navigation drawer like this

    app:itemBackground="@drawable/drawer_menu_selector"

fyi : need to define your 'app' namespace.

Antroid
  • 391
  • 4
  • 15
0

I searched for solution on this issue, tried everything, and only this solution worked for me.

You can find it on this link https://tuchangwei.github.io/2016/07/18/The-solution-that-the-menu-item-of-Navigation-View-can-t-change-its-background-When-it-is-selected-checked/

All the credit to https://tuchangwei.github.io/

sundjerBob
  • 95
  • 1
  • 1
  • 7