Navigation Drawer item background colour for selected item
Asked Answered
F

13

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?

Facer answered 13/3, 2014 at 9:48 Comment(3)
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 definedPeacoat
I think I've already tried that at some point. And the setItemChecked is used as it's part of Android Studios auto implementation.Facer
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.Putscher
F
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.

Facer answered 14/3, 2014 at 10:44 Comment(3)
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.Putscher
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?Facer
Where do you call getActivity().getBaseContext()? Could you provide some code?Sumerian
D
53

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

Disorient answered 14/1, 2015 at 5:31 Comment(6)
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.Arcturus
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).Beautiful
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);Konrad
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.Pose
It seems I spoke to soon. Neither of these solutions work for 4.2 devices :(Pose
doesnt work on Android O, background remains grey :(Stonybroke
D
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" />
Draught answered 9/10, 2016 at 19:11 Comment(0)
W
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" />
    
Wartime answered 24/6, 2016 at 12:52 Comment(1)
app:itemBackground="@drawable/item_bg" This works for me... thanksCatchfly
T
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.

Tod answered 29/7, 2015 at 10:17 Comment(3)
@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).Studnia
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.Tod
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.Studnia
E
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);

Exsect answered 13/11, 2014 at 5:22 Comment(0)
H
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>
Holmen answered 9/6, 2014 at 9:42 Comment(0)
C
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.

Counterattraction answered 13/3, 2014 at 11:35 Comment(4)
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.Facer
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.Counterattraction
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.Facer
Can you check out the edit I made and see if you have any insights? ThanksFacer
C
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.

Cima answered 14/3, 2014 at 9:20 Comment(2)
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.Facer
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 adapterCima
F
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.

Facer answered 14/3, 2014 at 10:44 Comment(3)
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.Putscher
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?Facer
Where do you call getActivity().getBaseContext()? Could you provide some code?Sumerian
I
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"/>
Indicant answered 7/2, 2015 at 12:55 Comment(0)
B
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()

Biofeedback answered 22/7, 2017 at 11:11 Comment(0)
C
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.

Consist answered 14/8, 2017 at 15:0 Comment(0)
P
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/

Phototopography answered 16/1, 2020 at 9:22 Comment(1)
On SO, you should point out how this link provides answer. Link only answer is not legalExtremism

© 2022 - 2024 — McMap. All rights reserved.