web-dev-qa-db-fra.com

Comment définir un comportement vérifiable partagé entre tous les groupes dans NavigationView?

J'ai créé deux groupes avec des identifiants uniques (j'ai besoin d'un séparateur) et ils ont tous les deux checkableBehavior réglé sur single. Cela permet à plusieurs éléments de différents groupes d'être vérifiés à la fois, et c'est exactement ce que j'essaie d'éviter. J'aimerais qu'un élément soit vérifié au maximum, dans tous les groupes.

Comme je n'ai trouvé aucun moyen de le faire en XML, j'ai essayé d'implémenter une logique simple dans onNavigationItemSelected pour décocher l'élément de menu précédent:

if (previousItem != null)
   previousItem.setChecked(false);
currentItem.setChecked(true);

mais la méthode setChecked(false) n'a jamais fonctionné pour moi - l'élément reste vérifié.

Voici mon exemple de code:

menu_navigation.xml:

<menu xmlns:Android="http://schemas.Android.com/apk/res/Android">
<group
        Android:id="@+id/nav_group_1"
        Android:checkableBehavior="single">
    <item
            Android:id="@+id/nav_feed"
            Android:title="@string/feed"/>
    <item
            Android:id="@+id/nav_people"
            Android:title="@string/people"/>
</group>
<group
        Android:id="@+id/nav_group_2"
        Android:checkableBehavior="single">
    <item
            Android:id="@+id/nav_settings"
            Android:title="@string/settings"/>
    <item
            Android:id="@+id/nav_help_feedback"
            Android:title="@string/help_feedback"/>
    <item
            Android:id="@+id/nav_logout"
            Android:title="@string/logout"/>
</group>

NavigationItemSelectedListener:

 mUiNavigationView.setNavigationItemSelectedListener(
                new NavigationView.OnNavigationItemSelectedListener() {
                    @Override
                    public boolean onNavigationItemSelected(MenuItem menuItem) {
                        if (previousItem != null)
                           previousItem.setChecked(false);
                        currentItem.setChecked(true);
                        //...
                        changeCurrentFragment(...);
                        return true;
                    }
                });

J'ai besoin d'un indice! Merci.

31
EyesClear

Voici la solution.

Étape 1: supprimer

Android:checkableBehavior="single"

des deux groupes.

Étape 2: ajoutez la logique suivante à l'écouteur:

mUiNavigationView.setNavigationItemSelectedListener(
            new NavigationView.OnNavigationItemSelectedListener() {
                @Override
                public boolean onNavigationItemSelected(MenuItem menuItem) {
                    menuItem.setCheckable(true);
                    menuItem.setChecked(true);
                    if (mPreviousMenuItem != null) {
                        mPreviousMenuItem.setChecked(false);
                    }
                    mPreviousMenuItem = menuItem;
                    //...
                    changeCurrentFragment(...);
                    return true;
                }
            });

Remarque: au lieu d'appeler menuItem.setCheckable(true), vous pouvez définir Android:checkable="true" Pour chaque élément en XML.

@ La solution de Moinkhan devrait également fonctionner (merci, vote positif), mais je ne voulais pas parcourir les éléments du menu chaque fois qu'une nouvelle position est sélectionnée.

37
EyesClear

En fait, vous n'avez pas besoin de groupes parallèles séparés pour les séparateurs. Vous pouvez avoir tout dans un groupe et y placer des sous-menus (avoir des titres) ou des sous-groupes (pas de titre). Il y aura des séparateurs pour ces sous-menus et sous-groupes. De cette façon, le comportement vérifiable fonctionne sans solution de contournement. (Fyi: C'est sur Design Support Lib 23.1.1)

Menu with dividers

<group
    Android:id="@+id/drawer_group"
    Android:checkableBehavior="single">
    <item
        Android:id="@+id/nav_1"
        Android:title="Menu1" />
    <item
        Android:id="@+id/nav_2"
        Android:title="Menu2" />
    <item
        Android:id="@+id/nav_3"
        Android:title="Menu3" />
    <item
        Android:id="@+id/nav_4"
        Android:title="Menu4" />

    <item
        Android:id="@+id/drawer_submenu"
        Android:title="Subheader">
        <menu>
            <group Android:checkableBehavior="single">
                <item
                    Android:id="@+id/nav_sub1_1"
                    Android:title="Menu_Sub1_1" />
                <item
                    Android:id="@+id/nav_sub1_2"
                    Android:title="Menu_Sub1_2" />
            </group>
        </menu>
    </item>

    <group Android:id="@+id/drawer_subgroup">
        <item
            Android:id="@+id/nav_subgroup_item"
            Android:title="Menu_Sub2_2" />
    </group>
</group>

Dans le code, je fais simplement les travaux de vérification suivants et uniques comme prévu:

@Override
public boolean onNavigationItemSelected(MenuItem item) {
    mNavigationView.setCheckedItem(item.getItemId());
    ...
}
9
Till

Pas besoin de supprimer checkableBehavior="single", Utilisez simplement

navigationView.setCheckedItem(item.getItemId());

au lieu de item.setChecked(true).

5
Jahid

Ok, j'ai trouvé la solution .. il suffit d'ajouter ce code d'extrait à la méthode onNavigationItemSelected

@Override
    public boolean onNavigationItemSelected(MenuItem menuItem) {
    Menu m = navView.getMenu();
    for (int i=0;i<m.size();i++) {
        MenuItem mi = m.getItem(i);
        if (!(mi.getItemId() == menuItem.getItemId())) {
            mi.setCheckable(false);
        }
    }
    menuItem.setCheckable(true);
    menuItem.setChecked(true);
    return false;
}

c'est tout .. Et oui setChecked (false) ne fonctionne pas. Tout simplement parce que de la liste du menu, il devrait y avoir un seul élément doit être mâché. Ainsi, vous ne pouvez la décocher que lorsque vous sélectionnez un autre élément. Et si vous cliquez sur l'élément sélectionné, la vue de navigation ne le décochera jamais. Tout simplement parce que le scénario que j'ai expliqué.

4
Moinkhan

Il semble y avoir un bogue d'invalidation dans l'implémentation de NavigationView, mais vous n'avez pas besoin d'utiliser setCheckable(), il vous suffit d'invalider le NavigationView après avoir appelé setChecked(false), ainsi:

    previousItem.setChecked(false);
    navigationView.invalidate();

Cependant, le groupe de menus ne doit pas avoir checkableBehavior="single", Car en mode exclusif, l'appel de setChecked(boolean) sur un MenuItem dans le groupe définira cet élément comme vérifié si vous passez vrai ou faux. Donc, pour que setChecked(false) fonctionne, vous devez supprimer checkableBehavior="single" De vos définitions de menu.

J'ai créé un problème à ce sujet ici: https://code.google.com/p/Android/issues/detail?id=178709

3
Lorne Laliberte

Voici une solution simple et douce que j'ai publiée ici :)

Faire des groupes différents fait un séparateur entre les deux mais crée le problème de deux éléments cochés dans le tiroir de navigation.

Une façon simple de gérer cela était:

 public boolean onNavigationItemSelected(final MenuItem menuItem) {

//if an item from extras group is clicked,refresh NAV_ITEMS_MAIN to remove previously checked item
if (menuItem.getGroupId() == NAV_ITEMS_EXTRA) {


    navigationView.getMenu().setGroupCheckable(NAV_ITEMS_MAIN, false, true);
    navigationView.getMenu().setGroupCheckable(NAV_ITEMS_EXTRA, true, true);
   }else{

    navigationView.getMenu().setGroupCheckable(NAV_ITEMS_MAIN, true, true);
    navigationView.getMenu().setGroupCheckable(NAV_ITEMS_EXTRA, false, true);


}
//Update highlighted item in the navigation menu
menuItem.setChecked(true);

}

1
Zorawar Sachdev