Cambiar el color de un elemento de menú marcado en un cajón de navegación

103

Estoy usando la nueva biblioteca de compatibilidad con diseño de Android para implementar un cajón de navegación en mi aplicación.

¡No sé cómo cambiar el color de un artículo seleccionado!

Aquí está el xml del menú:

<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group android:checkableBehavior="single">
    <item
        android:id="@+id/navigation_item_1"
        android:icon="@drawable/ic_1"
        android:title="@string/navigation_item_1"/>

    <item
        android:id="@+id/navigation_item_2"
        android:icon="@drawable/ic_2"
        android:title="@string/navigation_item_2"/>
</group>

Y aquí está el xml de navigationview que se coloca dentro de un android.support.v4.widget.DrawerLayout:

<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:menu="@menu/menu_drawer">

    <TextView
        android:id="@+id/main_activity_version"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"
        android:layout_marginBottom="@dimen/activity_vertical_margin"
        android:layout_marginLeft="@dimen/activity_horizontal_margin"
        android:textColor="@color/primary_text" />

</android.support.design.widget.NavigationView>

Gracias por tu ayuda !

[EDITAR] Ya he visto soluciones como esta: Cambiar el color de fondo del menú de Android .

Parece ser un gran truco y pensé que con la nueva Biblioteca de soporte de diseño, ¿se habría introducido algo más limpio?

Greg
fuente
posible duplicado de cambiar color de fondo del menú de Android
jlopez

Respuestas:

244

Bueno, puedes lograr esto usando Color State Resource . Si notas dentro de tu NavigationViewestás usando

app:itemIconTint="@color/black"
app:itemTextColor="@color/primary_text"

Aquí, en lugar de usar @color/blacko @color/primary_test, use un Color State List Resource. Para eso, primero cree un nuevo directorio xmlinterno (por ejemplo, drawer_item.xml) color(que debería estar dentro del resdirectorio). Si aún no tiene un directorio nombrado color, cree uno.

Ahora adentro drawer_item.xmlhaz algo como esto

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:color="checked state color" android:state_checked="true" />
    <item android:color="your default color" />
</selector>

El último paso sería cambiar tu NavigationView

<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/drawer_item"  // notice here
    app:itemTextColor="@color/drawer_item" // and here
    app:itemBackground="@android:color/transparent"// and here for setting the background color to tranparent
    app:menu="@menu/menu_drawer">

Como no se puede utilizar de lista de recursos estado de color separados para IconTint, ItemTextColor, ItemBackground.

Ahora, cuando configura un elemento como marcado (ya sea en xmlo programáticamente), el elemento en particular tendrá un color diferente al de los no seleccionados.

Sash_KP
fuente
Recuerde que para presionar para que funcione, debe cambiarlo de android: state_checked a android: state_pressed.
Programista
32
para ItemBackground, debe usar un dibujable en lugar de color porque no puede definir un fondo usando un recurso de color.
sirFunkenstine
@sash, si queremos cambiar la imagen del icono en el elemento de navegación seleccionado, ¿cómo lo haremos?
Mohit
@sirFunkenstine Si está usando el selector de color, puede ponerlo en la carpeta de color en su carpeta res.
Kishan Vaghela
@KishanVaghela haciendo lo que sugiere produce este error: Línea de archivo XML binario n. ° 3: la etiqueta <item> requiere un atributo 'dibujable' o una etiqueta secundaria que defina un elemento
dibujable
66

Creo que app:itemBackgroundespera un dibujable. Así que sigue los pasos a continuación:

Haga un archivo dibujable highlight_color.xmlcon el siguiente contenido:

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

Cree otro archivo dibujable nav_item_drawable.xmlcon el siguiente contenido:

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

Finalmente agregue la app:itemBackgroundetiqueta en 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">

aquí, el archivo highlight_color.xml define un color sólido que se puede dibujar para el fondo. Posteriormente, este color dibujable se asigna al selector nav_item_drawable.xml.

Esto funcionó para mí. Ojalá esto ayude.

******************************************** ACTUALIZADO *** *****************************************

Aunque la respuesta mencionada anteriormente le brinda un control preciso sobre algunas propiedades, la forma en que estoy a punto de describir se siente más SÓLIDA y es un poco MÁS FRÍA .

Entonces, lo que puede hacer es definir un ThemeOverlay en styles.xmlel NavigationView de esta manera:

    <style name="ThemeOverlay.AppCompat.navTheme">

        <!-- Color of text and icon when SELECTED -->
        <item name="colorPrimary">@color/color_of_your_choice</item> 

        <!-- Background color when SELECTED -->
        <item name="colorControlHighlight">@color/color_of_your_choice</item> 

    </style>

ahora aplique este ThemeOverlay al app:themeatributo de NavigationView, así:

<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:theme="@style/ThemeOverlay.AppCompat.navTheme"
app:headerLayout="@layout/drawer_header"
app:menu="@menu/menu_drawer">

Espero que esto sea de ayuda.

Ankush
fuente
1
Además, este método se puede utilizar como android:background="@drawable/nav_item_drawable"para otros widgets como RadioButton, Checkbox, Button, etc. Reduce la programación de bloatware para su manejo setOnCheckedChangeListenersolo para resaltar el color.
rupinderjeet
@Ankush esto funciona pero el texto y el icono desaparecen, también he configurado el color del tinte del elemento, pero no funciona. ¿Puede sugerirme cómo se puede hacer?
Usuario
1
@User No sé qué salió mal con su código, pero lo agregué a la respuesta. Una forma completamente diferente de lograr lo mismo con menos esfuerzo. Puedes comprobarlo.
Ankush
1
¡Esto debería aceptarse como una respuesta! Muchas gracias, muy útil !!!
Svetlana Rozhkova
4

Es necesario establecer la NavigateItemcasilla de verificación verdadera siempre que NavigateViewse haga clic en un elemento.

//listen for navigation events
NavigationView navigationView = (NavigationView)findViewById(R.id.navigation);
navigationView.setNavigationItemSelectedListener(this);
// select the correct nav menu item
navigationView.getMenu().findItem(mNavItemId).setChecked(true);

Añadir NavigationItemSelectedListenerelNavigationView

  @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;
  }
Vikalp Patel
fuente
Gracias por tu ayuda Vikalp, pero ya lo estoy haciendo ( setChecked(true)). Puedo ver que cambia el color del elemento marcado, pero no puedo modificarlo yo mismo, el color siempre es una versión más clara del fondo de la vista de navegación.
Greg
Predeterminado @ Greg Por setChecked(true)el Viewcolor de fondo cambia hasta que el tema dispositivo que utiliza. Si desea cambiar el fondo del elemento a otro color, debe inflar su diseño en DrawerLayouto NavigationViewy manejarlo usted mismo.
Vikalp Patel
gracias de nuevo, he intentado hacer lo que me dijiste pero sin éxito, ¿tendrías un enlace explicando como por favor?
Greg
2

Esta es otra forma de lograr esto:

public boolean onOptionsItemSelected(MenuItem item) {

    int id = item.getItemId();

    item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
        @Override
        public boolean onMenuItemClick(MenuItem item) {
            item.setEnabled(true);
            item.setTitle(Html.fromHtml("<font color='#ff3824'>Settings</font>"));
            return false;
            }
        });


    //noinspection SimplifiableIfStatement
    if (id == R.id.action_settings) {
        return true;
    }

    return super.onOptionsItemSelected(item);
}

}

Abhishek
fuente
Mi pregunta era qué pasa si quiero cambiar el color del elemento seleccionado del menú emergente, pero gracias a usted que obtuve una gran idea de esta solución para cambiar el color del elemento del menú seleccionado ... ¡así que le doy voto! Y la solución es como :: item.setTitle (Html.fromHtml ("<font color = '# ff3824'> Configuración </font>"));
Tarit Ray
1

Así es como puede hacerlo en el método onCreate de su actividad:

NavigationView navigationView = findViewById(R.id.nav_view);
ColorStateList csl = new ColorStateList(
    new int[][] {
        new int[] {-android.R.attr.state_checked}, // unchecked
        new int[] { android.R.attr.state_checked}  // checked
    },
    new int[] {
        Color.BLACK,
        Color.RED
    }
);
navigationView.setItemTextColor(csl);
navigationView.setItemIconTintList(csl);
tguen
fuente
1

Paso 1: cree un selector marcado / no marcado:

selector.xml

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

Paso 2: use el atributo xml app:itemTextColordentro del NavigationViewwidget para seleccionar el color del texto.

<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:headerLayout="@layout/navigation_header_layout"
    app:itemTextColor="@drawable/selector"
    app:menu="@menu/navigation_menu" />

Paso 3:
Por alguna razón, cuando presiona un elemento del NavigationViewmenú, no lo considera una verificación de botón. Por lo tanto, debe verificar manualmente el elemento seleccionado y borrar el elemento seleccionado anteriormente. Utilice el siguiente oyente para hacer eso

@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {

    int id = item.getItemId();

    // remove all colors of the items to the `unchecked` state of the selector
    removeColor(mNavigationView);

    // check the selected item to change its color set by the `checked` state of the selector
    item.setChecked(true);

    switch (item.getItemId()) {
      case R.id.dashboard:
          ...
    }

    drawerLayout.closeDrawer(GravityCompat.START);
    return true;
}

private void removeColor(NavigationView view) {
    for (int i = 0; i < view.getMenu().size(); i++) {
        MenuItem item = view.getMenu().getItem(i);
        item.setChecked(false);
    }
}

Paso 4:
Para cambiar el color del icono, use el app:iconTintatributo en los NavigationViewelementos del menú y establezca el mismo selector.

<?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/nav_account"
        android:checked="true"
        android:icon="@drawable/ic_person_black_24dp"
        android:title="My Account"
        app:iconTint="@drawable/selector" />
    <item
        android:id="@+id/nav_settings"
        android:icon="@drawable/ic_settings_black_24dp"
        android:title="Settings"
        app:iconTint="@drawable/selector" />

    <item
        android:id="@+id/nav_logout"
        android:icon="@drawable/logout"
        android:title="Log Out"
        app:iconTint="@drawable/selector" />
</menu>

Resultado:

Zain
fuente