Changer la couleur d'un élément de menu coché dans un tiroir de navigation

103

J'utilise la nouvelle bibliothèque Android Design Support pour implémenter un tiroir de navigation dans mon application.

Je n'arrive pas à comprendre comment changer la couleur d'un élément sélectionné!

Voici le xml du menu:

<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>

Et voici le navigationview xml qui est placé dans 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>

Merci de votre aide !

[EDIT] J'ai déjà examiné des solutions telles que celle-ci: Changer la couleur de fond du menu Android .

Cela semble être un hack et je pensais qu'avec la nouvelle bibliothèque de support de conception, quelque chose de plus propre aurait été introduit?

Greg
la source

Réponses:

244

Eh bien, vous pouvez y parvenir en utilisant Color State Resource . Si vous remarquez NavigationViewque vous utilisez

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

Ici, au lieu d'utiliser @color/blackou @color/primary_test, utilisez un Color State List Resource. Pour cela, créez d'abord un nouveau xmlrépertoire (par exemple, tiroir_item.xml) dans le colorrépertoire (qui devrait être à l'intérieur du resrépertoire.) Si vous n'avez pas déjà un répertoire nommé color, créez-en un.

Maintenant à l'intérieur drawer_item.xmlfais quelque chose comme ça

<?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>

La dernière étape serait de changer votre 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">

Comme cela , vous pouvez utiliser des ressources Liste séparée Couleur Etat pour IconTint, ItemTextColor, ItemBackground.

Désormais, lorsque vous définissez un élément comme étant coché (soit dans xmlou par programme), l'élément particulier aura une couleur différente de celle non cochée.

Sash_KP
la source
N'oubliez pas que pour que pressé fonctionne, vous devez le changer d'Android: state_checked en android: state_pressed.
Programista
32
pour ItemBackground, vous devez utiliser un dessin au lieu de la couleur car vous ne pouvez pas définir un arrière-plan à l'aide d'une ressource de couleur.
sirFunkenstine
@sash si nous voulons changer l'image de l'icône sur l'élément de navigation sélectionné, comment procéderons-nous?
mohit
@sirFunkenstine Si vous utilisez le sélecteur de couleur, vous pouvez le placer dans le dossier couleur de votre dossier res.
Kishan Vaghela le
@KishanVaghela faisant ce que vous suggérez produit cette erreur: Ligne de fichier XML binaire n ° 3: la balise <item> nécessite un attribut 'drawable' ou une balise enfant définissant un dessinable
iOSAndroidWindowsMobileAppsDev
66

Je crois app:itemBackgrounds'attend à un tirable. Suivez donc les étapes ci-dessous:

Créez un fichier dessinable highlight_color.xmlavec le contenu suivant:

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

Créez un autre fichier dessinable nav_item_drawable.xmlavec le contenu suivant:

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

Enfin, ajoutez une app:itemBackgroundbalise dans 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">

ici, le fichier highlight_color.xml définit une couleur unie pouvant être dessinée pour l'arrière-plan. Plus tard, cette couleur dessinable est assignée au sélecteur nav_item_drawable.xml.

Cela a fonctionné pour moi. J'espère que cela aidera.

********************************************** MISE À JOUR *** *******************************************

Bien que la réponse mentionnée ci-dessus vous donne un contrôle précis sur certaines propriétés, mais la façon dont je suis sur le point de décrire semble plus SOLIDE et un peu PLUS FRAÎCHE .

Donc, vous pouvez définir un ThemeOverlay dans le styles.xmlpour le NavigationView comme ceci:

    <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>

appliquez maintenant ce ThemeOverlay à l' app:themeattribut de NavigationView, comme ceci:

<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">

J'espère que cela aidera.

Ankush
la source
1
En outre, cette méthode peut être utilisée comme android:background="@drawable/nav_item_drawable"pour d'autres widgets comme RadioButton, Checkbox, Button, etc. Réduit la programmation bloatware pour la gestion setOnCheckedChangeListenerjuste pour la mise en évidence des couleurs.
rupinderjeet
@Ankush cela fonctionne mais le texte et l'icône disparaissent, j'ai également défini la couleur de teinte de l'élément mais cela ne fonctionne pas. pouvez-vous s'il vous plaît me suggérer comment cela peut être fait
Utilisateur
1
@User Je ne sais pas ce qui n'a pas fonctionné avec votre code, mais j'ai ajouté à la réponse. Une manière totalement différente de réaliser la même chose avec moins d'effort. Vous pouvez vérifier cela.
Ankush
1
Cela devrait être accepté comme une réponse! Merci beaucoup, très utile !!!
Svetlana Rozhkova le
4

Il est nécessaire de définir la NavigateItemcase à cocher true à chaque NavigateViewclic sur l' élément

//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);

Ajouter NavigationItemSelectedListenersurNavigationView

  @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
la source
Merci pour votre aide Vikalp, mais je le fais déjà ( setChecked(true)). Je peux voir la couleur de l'élément coché changer mais je ne peux pas le modifier moi-même, la couleur est toujours une version plus claire de l'arrière-plan de la vue de navigation.
Greg
@Greg Par défaut setChecked(true), Viewchange la couleur d'arrière-plan du thème que vous utilisez . Si vous changez l'arrière-plan de l'article en une autre couleur, vous devez gonfler votre mise en page DrawerLayoutou NavigationViewet la gérer vous-même.
Vikalp Patel
merci encore, j'ai essayé de faire ce que vous m'avez dit mais sans succès, auriez-vous un lien expliquant comment s'il vous plaît?
Greg
2

Voici une autre façon d'y parvenir:

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
la source
Mon dobut était de savoir si je voulais changer la couleur de l'élément sélectionné du menu contextuel, mais grâce à vous, j'ai eu une excellente idée de votre solution pour changer la couleur de l'élément de menu sélectionné ... donc vous donner le vote !!! Et le travail autour est comme: item.setTitle (Html.fromHtml ("<font color = '# ff3824'> Paramètres </font>"));
Tarit Ray
1

Voici comment vous pouvez le faire dans la méthode onCreate de votre activité:

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
la source
1

Étape 1: Créez un sélecteur coché / non coché:

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>

Étape 2: utilisez l'attribut xml app:itemTextColordans le NavigationViewwidget pour sélectionner la couleur du texte.

<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" />

Étape 3:
Pour une raison quelconque, lorsque vous appuyez sur un élément du NavigationViewmenu, cela ne le considère pas comme une vérification de bouton. Vous devez donc faire cocher manuellement l'élément sélectionné et effacer l'élément précédemment sélectionné. Utilisez l'auditeur ci-dessous pour le faire

@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);
    }
}

Étape 4:
Pour changer la couleur de l'icône, utilisez l' app:iconTintattribut dans les NavigationViewéléments de menu et définissez-le sur le même sélecteur.

<?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>

Résultat:

Zain
la source