How to customize item background and item text color inside NavigationView?
Asked Answered
I

9

79

I wanna achieve something like this shown in the Material Design Docs.

colorControlHighlight is used for the Background on checked items.

I need to customize:

  • background unchecked
  • text color checked
  • text color unchecked
Implore answered 2/6, 2015 at 10:52 Comment(0)
D
11

With the MaterialComponents Library you can use these attributes:

  • app:itemShapeFillColor: background item color
  • app:itemIconTint: icon tint
  • app:itemTextColor: text color

In the layout:

<com.google.android.material.navigation.NavigationView
    app:itemShapeFillColor="@color/shape_selector"
    app:itemIconTint="@color/icon_tint_selector"
    app:itemTextColor="@color/text_color_selector"
    ../>

In a custom style:

<style name="..." parent="Widget.MaterialComponents.NavigationView" >
   <item name="itemShapeFillColor">@color/shape_selector</item>
   <item name="itemIconTint">@color/icon_tint_selector</item>
   <item name="itemTextColor">@color/text_color_selector</item>
</style>

For the itemIconTint and itemTextColor you can use a selector like this:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
  <item android:color="?attr/colorPrimary" android:state_checked="true"/>
  <item android:alpha="0.38" android:color="?attr/colorOnSurface" android:state_enabled="false"/>
  <item android:color="?attr/colorOnSurface"/>
</selector>

For the itemShapeFillColor you can use a selector like:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
  <item android:alpha="0.12" android:color="?attr/colorPrimary" android:state_activated="true"/>
  <item android:alpha="0.12" android:color="?attr/colorPrimary" android:state_checked="true"/>
  <item android:color="@android:color/transparent"/>
</selector>

Just a final note. Pay attention to use to the itemBackground.
It is set to @null to use a shaped background programmatically generated by NavigationView when itemShapeAppearance and/or itemShapeAppearanceOverlay is set (default behaviour).
This background is styled using the itemShape* attributes.
Setting itemBackground will overwrite the programmatic background and cause values set in the itemShape* attributes to be ignored.

enter image description here

Deakin answered 14/5, 2020 at 8:37 Comment(0)
B
133

itemBackground, itemIconTint and itemTextColor are simple xml-attributes that can be set, though you have to use a custom prefix instead of the android: one.

Example

<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true">

    <!-- Other layout views -->

    <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:itemBackground="@drawable/my_ripple"
        app:itemIconTint="#2196f3"
        app:itemTextColor="#009688"
        app:headerLayout="@layout/nav_header"
        app:menu="@menu/drawer_view" />

</android.support.v4.widget.DrawerLayout>

Note: In this case the text color, icon tint and background are static. If you want to change the color of the text (e.g. pink when unchecked and teal when checked) you should use a ColorStateList.

Example

Create a new *.xml file in /res/color - let's name it state_list.xml - with the following content:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- This is used when the Navigation Item is checked -->
    <item android:color="#009688" android:state_checked="true" />
    <!-- This is the default text color -->
    <item android:color="#E91E63" />
</selector>

and then simply reference it like this: app:itemTextColor="@color/state_list"

The same goes for itemIconTint. itemBackground expects a resource id. See the docs as well.

Belen answered 2/6, 2015 at 11:30 Comment(8)
for item background in checked item just use <item name="colorControlHighlight">#123456</item>Implore
That's true but this could also change the color of other views like EditText at least if you define it in your global Theme.Belen
Anyone having problems when setting app:itemBackground="@drawable/my_ripple"? It happens to me that when I press an item the one in the very bottom reflects the ripple effect instead of the one I am actually pressing.Tortosa
@JavierMendonca I've experienced the same but I don't know a fix for this atm - most likely this is a bug but maybe it's worth asking a separate question for this specific issue.Belen
app:itemBackground doesn't work as expected. Am I the only one who faced this problem?Lethargic
Remember that for pressed to work you need to change it from android:state_checked to android:state_pressed.Brachy
Is it possible to do this on individual items? Different colors on every item?Guideline
@JohnErnestGuadalupe Probably you can do that, but you will have to get the menu item from the drawer and then play with each of the menu items individually.Saxton
B
98

NavigationDrawer(NavigationView) has three options for configuration of checked/selected items.

app:itemIconTint="@color/menu_text_color" //icon color
app:itemTextColor="@color/menu_text_color" //text color
app:itemBackground="@drawable/menu_background_color" //background

Icon and text color

First two options ( icon and text ) need color state list resource - https://developer.android.com/guide/topics/resources/color-list-resource.html.

Such menu_text_color resource needs to be created in res/color. This file content should look similar to:

<!-- res/color/menu_text_color.xml -->
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
  <item android:color="@color/colorWhite" android:state_checked="true" />
  <item android:color="@color/colorBlack" android:state_checked="false"/>
</selector>
  • @color/colorWhite - color resource used for checked item

  • @color/colorBlack - color resource used for unchecked item

I have created one resource for both, but it is possible to create two separated files - one for text, one for icon.

Background (itemBackground)

Background option needs drawable resource instead of color, every try to set color will end by exception. Drawable resource need to be created in res/drawable and its content should look similar to:

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

There is no need to created any drawables which simulates color ( in other solutions I saw such propositions - maybe for older sdk version ), color can be used in this file directly. In this example file I am using transparent color for not checked item and colorPrimary for checked item.

Troubleshooting and important notes

  • In background resource always use state_checked="false" instead of default, with default color it will not work
  • For dynamic/programmatically created menu remember to set items as checkable:

Code example ( dynamic menu item add ):

  menu.add(group_id, item_id, Menu.NONE, item_name).setCheckable(true).setChecked(false);

If items will not be set as checkable then background will not work ( text and icon color surprising will work as expected ).

Binturong answered 28/12, 2016 at 16:50 Comment(2)
good answer but i prefer to create a theme for navigationview. which attr i need to override?Implore
This is the most important thing else nothing works. remember to set items as checkable. Thank you for mentioning this, which no one did.Antioch
D
11

With the MaterialComponents Library you can use these attributes:

  • app:itemShapeFillColor: background item color
  • app:itemIconTint: icon tint
  • app:itemTextColor: text color

In the layout:

<com.google.android.material.navigation.NavigationView
    app:itemShapeFillColor="@color/shape_selector"
    app:itemIconTint="@color/icon_tint_selector"
    app:itemTextColor="@color/text_color_selector"
    ../>

In a custom style:

<style name="..." parent="Widget.MaterialComponents.NavigationView" >
   <item name="itemShapeFillColor">@color/shape_selector</item>
   <item name="itemIconTint">@color/icon_tint_selector</item>
   <item name="itemTextColor">@color/text_color_selector</item>
</style>

For the itemIconTint and itemTextColor you can use a selector like this:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
  <item android:color="?attr/colorPrimary" android:state_checked="true"/>
  <item android:alpha="0.38" android:color="?attr/colorOnSurface" android:state_enabled="false"/>
  <item android:color="?attr/colorOnSurface"/>
</selector>

For the itemShapeFillColor you can use a selector like:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
  <item android:alpha="0.12" android:color="?attr/colorPrimary" android:state_activated="true"/>
  <item android:alpha="0.12" android:color="?attr/colorPrimary" android:state_checked="true"/>
  <item android:color="@android:color/transparent"/>
</selector>

Just a final note. Pay attention to use to the itemBackground.
It is set to @null to use a shaped background programmatically generated by NavigationView when itemShapeAppearance and/or itemShapeAppearanceOverlay is set (default behaviour).
This background is styled using the itemShape* attributes.
Setting itemBackground will overwrite the programmatic background and cause values set in the itemShape* attributes to be ignored.

enter image description here

Deakin answered 14/5, 2020 at 8:37 Comment(0)
W
9

Using colorControlHighlight is a good solution to me. Be aware that with the latest support library, you can define a theme (not just the style) for every widget; for example you can define the colorControlHighlight into the NavigationView theme and this will not be applied to the rest of widgets.

Whirlabout answered 4/6, 2015 at 15:3 Comment(2)
perfect answer but which attr i need to override in NavigationView theme to control background, textcolor and iconcolor?Implore
yeah sure, create a style with <item name="android:colorControlHighlight">@color/navigationDrawerTextNight</item> but how is it applied to the menu item text ?? itemTextColor doesn't exist in a stylePartial
C
6

If you want change only one menu item color from your activity based in events, see this blog by HANIHASHEMI:

https://hanihashemi.com/2017/05/06/change-text-color-of-menuitem-in-navigation-drawer/

private void setTextColorForMenuItem(MenuItem menuItem, @ColorRes int color) {
  SpannableString spanString = new SpannableString(menuItem.getTitle().toString());
  spanString.setSpan(new ForegroundColorSpan(ContextCompat.getColor(this, color)), 0, spanString.length(), 0);
  menuItem.setTitle(spanString);
}

Call method

setTextColorForMenuItem(item, R.color.colorPrimary);

If you work with Xamarin Android try this:

private void SetTextColorForMenuItem(IMenuItem menuItem, Android.Graphics.Color color)
        {
            SpannableString spanString = new SpannableString(menuItem.TitleFormatted.ToString());
            spanString.SetSpan(new ForegroundColorSpan(color), 0, spanString.Length(), 0);
            menuItem.SetTitle(spanString);
        }

Call Method:

SetTextColorForMenuItem(navigationView.Menu.GetItem(0), Android.Graphics.Color.OrangeRed);
Caravette answered 3/1, 2018 at 17:5 Comment(0)
I
5

You can use programmatically this code :

int[][] states = new int[][] {
    new int[] { android.R.attr.state_enabled}, // enabled
    new int[] {-android.R.attr.state_enabled}, // disabled
    new int[] {-android.R.attr.state_checked}, // unchecked
    new int[] { android.R.attr.state_pressed}  // pressed
};

int[] colors = new int[] {
    Color.BLACK,
    Color.RED,
    Color.GREEN,
    Color.BLUE
};

ColorStateList myList = new ColorStateList(states, colors);

  nav_view.setItemIconTintList(myList);
Inna answered 16/4, 2016 at 15:4 Comment(0)
O
3

Now, in navigation view you can also provide your own item view. With new appcompat-v7:23.1.0 you can

set custom views for items via app:actionLayout or using MenuItemCompat.setActionView().

View view = View.inflate(context, R.layout.your_custom_nav_layout_item, null);
MenuItemCompat.setActionView(menuItem, view); 

This way you can create your own layout with TextView and change backgrounds/colors/fonts however you want. Hope this was helpful :) Source

Octaviaoctavian answered 19/10, 2015 at 10:40 Comment(0)
C
0

You can do it using the following statement:

navigationView.setItemBackground(ContextCompat.getDrawable(CustomerHomeActivity.this, R.color.transparent));
Credulity answered 1/10, 2015 at 14:45 Comment(0)
G
0

If you want to do this programmatically:

Based on Jhon's answer:

You can use Kotlin extension like this:

fun NavigationView.setTextColorForMenuItems(@ColorInt color: Int) {
    for (i: Int in 0 until menu.size()) {
        val menuItem = menu.getItem(i)
        val spanString = SpannableString(menuItem.title.toString())
        spanString.setSpan(ForegroundColorSpan(color), 0, spanString.length, 0)
        menuItem.title = spanString
    }
}

Then call

nav_view.setTextColorForMenuItems(Color.BLACK)
Gabar answered 12/9, 2019 at 7:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.