Comment créer un simple diviseur dans le nouveau NavigationView?

154

Google a introduit le NavigationViewdans la bibliothèque de support de conception version 22.2.0 avec lequel vous pouvez créer un tiroir très facilement à l'aide d'une ressource de menu.

Comment créer une ligne de séparation simple entre deux éléments? Le regroupement des éléments n'a pas fonctionné. La création d'une section de sous-éléments crée une ligne de séparation, mais elle nécessite un titre, ce que je ne veux pas.

Toute aide serait appréciée.

Longi
la source
Comme indiqué dans les commentaires, le problème avec la réponse acceptée est que le comportement vérifiable ne fonctionne pas sur plusieurs groupes (parallèles). Pour éviter cela, ne créez pas de groupes parallèles, mais utilisez des sous-menus ou des sous-groupes pour obtenir vos diviseurs comme décrit dans ma réponse ici: stackoverflow.com/questions/30766919/...
Jusqu'au

Réponses:

319

Tout ce que vous avez à faire est de définir un groupavec un identifiant unique , j'ai vérifié l'implémentation si le groupe a des identifiants différents, cela créera un diviseur.

Exemple de menu, création du séparateur:

<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    tools:context=".MainActivity">

    <group android:id="@+id/grp1" android:checkableBehavior="single" >
        <item
            android:id="@+id/navigation_item_1"
            android:checked="true"
            android:icon="@drawable/ic_home"
            android:title="@string/navigation_item_1" />
    </group>

    <group android:id="@+id/grp2" android:checkableBehavior="single" >
        <item
            android:id="@+id/navigation_item_2"
            android:icon="@drawable/ic_home"
            android:title="@string/navigation_item_2" />
    </group>
</menu>
New Jersey
la source
9
Je me demande pourquoi cela (pour autant que je sache) n'est pas documenté. Je pense que ce sera beaucoup demandé. Merci!
Gaëtan
16
Le seul problème avec cette approche est qu'elle setCheckedsemble fonctionner au niveau du groupe. Si vous sélectionnez un article dans le groupe A, puis ouvrez à nouveau le tiroir et sélectionnez l'article dans le groupe B, les deux articles resteront en surbrillance. Peut-être que Google corrigera ce problème dans la prochaine version, mais pour l'instant, c'est l'inconvénient d'utiliser plusieurs groupes avec NavigationView.
hungryghost
3
Génial. À propos de la double vérification, essayez android:checkableBehavior="none"pour votre deuxième groupe (ce sont des actions, pas de navigation, je suppose)
espinchi
12
Chose amusante, si vous supprimez l'identifiant du fichier, groupil sera compilé et exécuté mais les diviseurs sont masqués.
Vahid Amiri
5
Cela ne fonctionne pas non plus pour moi. Je voulais des lignes entre les groupes de menus, pas après chaque élément.
Rich Morey
54

créer un tiroir_item_bg.xml pouvant être dessiné comme celui-ci,

    <layer-list xmlns:android="http://schemas.android.com/apk/res/android">

    <item>
        <shape android:shape="rectangle" >
            <solid android:color="#F4F4F4" />
        </shape>
    </item>

    <item android:top="-2dp" android:right="-2dp" android:left="-2dp">
        <shape>
            <solid android:color="@android:color/transparent" />
            <stroke
                android:width="1dp"
                android:color="#EAEAEA" />
        </shape>
        <!--
        android:dashGap="10px"
                android:dashWidth="10px"
                -->
    </item>

</layer-list>

et ajoutez-le à NavigationView en tant qu'application: itemBackground = "@ drawable / tiroir_item_bg"

<android.support.design.widget.NavigationView
        android:id="@+id/nav_view"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:background="#F4F4F4"
        android:layout_gravity="start"
        android:fitsSystemWindows="false"
        app:menu="@menu/activity_main_drawer"
        app:itemBackground="@drawable/drawer_item_bg"/>

et c'est reparti...entrez la description de l'image ici

vbp
la source
1
cela fonctionne, mais cela supprime également le remplissage gauche de l'icône de l'élément. au moins dans mon code, pas dans votre capture d'écran pour une raison quelconque
luky
@vbp J'ai besoin de la bordure supérieure pour le premier enfant, de la bordure inférieure pour l'autre enfant. Comment pourrais-je y parvenir. C'est quelque chose de similaire à id.first child en css
Prabs
@Prabs envisage d'utiliser un fragment, une vue de
recyclage
1
J'ai fait navMenuView.addItemDecoration(new DividerItemDecoration(NavigationViewActivity.this, DividerItemDecoration.VERTICAL));pour une bordure d'objet parfaite
Prabs
19

Ajout simple de DeviderItemDecoration:

NavigationView navigationView = (NavigationView) findViewById(R.id.navigation);
NavigationMenuView navMenuView = (NavigationMenuView) navigationView.getChildAt(0);
navMenuView.addItemDecoration(new DividerItemDecoration(MainActivity.this,DividerItemDecoration.VERTICAL));

Cela ressemble à ceci:

entrez la description de l'image ici

SANAT
la source
Puis-je changer la hauteur de la addItemDecorationligne à 1px?
Prabs
Merci votre solution a fonctionné pour moi. J'apprécie. Bro une autre question avec ça. Est-il possible de supprimer la bordure supérieure du premier élément et de définir des bordures uniquement au bas des éléments?
viper
@viper veuillez vous référer à ceci: bignerdranch.com/blog/…
SANAT
1
Ce type de séparateur pour chaque élément ne suit pas Material Guyidelines
Boris Ruzanov
19

Vous pouvez facilement ajouter des séparateurs en définissant l'arrière-plan de l'élément de menu via XML en utilisant app:itemBackground

<android.support.design.widget.NavigationView
    android:id="@id/drawer_navigation_view"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_gravity="start"
    android:fitsSystemWindows="true"
    app:menu="@menu/all_navigation_menu"
    app:itemIconTint="@color/colorPrimary"
    app:itemBackground="@drawable/bg_drawer_item"
    android:background="@color/default_background"/>

Et utilisez LayerDrawable comme arrière-plan. Il préserve la superposition d'ondulation de conception matérielle pour les clics.

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape android:shape="rectangle">
            <solid android:color="@color/white"/>
        </shape>
    </item>
    <item android:left="@dimen/activity_horizontal_margin">
        <shape android:shape="rectangle">
            <solid android:color="@color/divider"/>
        </shape>
    </item>
    <item android:bottom="1dp">
        <shape android:shape="rectangle">
            <solid android:color="@color/white"/>
        </shape>
    </item>
</layer-list>

Le résultat:

entrez la description de l'image ici

Stanislav Perchenko
la source
2
semble être la meilleure réponse et aucun groupe impliqué
Michał Ziobro
Que faire si vous souhaitez utiliser une couleur d'arrière-plan personnalisée pour l'élément sélectionné?
ataravati
J'ai une erreur sur <shape>: L'élément n'est pas autorisé ici
Sébastien REMY
11

Je pense avoir une solution encore meilleure pour le problème de plusieurs éléments vérifiés. En utilisant ma façon, vous n'avez pas à vous soucier de changer votre code lors de l'ajout de nouvelles sections à votre menu. Mon menu ressemble à la solution acceptée écrite par Jared, à la différence d'utiliser andoid: checkableBehavior = " all " sur les groupes:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <group android:id="@+id/first_section" android:checkableBehavior="all">
        <item
            android:id="@+id/frontpage"
            android:icon="@drawable/ic_action_home_24dp_light_blue"
            android:title="@string/drawer_frontpage" />
        <item
            android:id="@+id/search"
            android:icon="@drawable/ic_search"
            android:title="@string/drawer_search" />
    </group>
    <group android:id="@+id/second_section" android:checkableBehavior="all">
        <item
            android:id="@+id/events"
            android:icon="@drawable/ic_maps_local_movies_24dp_light_blue"
            android:title="@string/drawer_events" />
    </group>
</menu>

Le checkableBehavior de 'all' permet de cocher / décocher des éléments uniques à volonté, indépendamment du groupe auquel ils appartiennent. Il vous suffit de stocker le dernier menuitem vérifié. Le code java ressemble à ceci:

private MenuItem activeMenuItem;

@Override
public boolean onNavigationItemSelected(MenuItem menuItem) {
    // Update selected/deselected MenuItems
    if (activeMenuItem != null)
        activeMenuItem.setChecked(false);
    activeMenuItem = menuItem;
    menuItem.setChecked(true);

    drawerLayout.closeDrawers();
    return true;
}
plexus
la source
8

Faire différents groupes comme la réponse de Nilesh crée 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);
}
Zorawar Sachdev
la source
Encore plus simple:android:checkableBehavior="none"
espinchi
2
@espinchi - Cela ne fonctionnera pas si d'autres groupes contiennent des éléments de menu de navigation. Cette solution ne peut fonctionner que pour les actions. Pas une bonne pratique UX
Mushtaq Jameel
Excellent! Cela pourrait être plus clair si vous avez changé vos constantes non définies NAV_ITEMS_MAIN et NAV_ITEMS_EXTRA avec R.id.nav_items_group_main ou R.id.nav_items_group_extra et ajoutez le XML requis à votre exemple
ChrisPrime
IS onNavigationItemSelected (MenuItem final menuItem) {Méthode par défaut ?? où dois-je faire ce code?
John
et qu'est-ce que NAV_ITEMS_MAIN ??
John
8

Je ne sais pas si cela est résolu API 26 (Android 8)ou si c'était possible tout le temps. Je suis toujours un noob dans la programmation Android. Cependant, j'ai ajouté des groupes de parents comme ci-dessous. Test sur téléphone physique Android 6,

  1. J'ai le diviseur
  2. La sélection d'un élément parmi nav_g1ou nav_g2désélectionnera d'autres éléments.
  3. Aucun remplissage supplémentaire ajouté en raison des groupes imbriqués.
  4. Je n'ai ajouté aucun Javacode aux auditeurs

Code de menu

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <group android:checkableBehavior="single">
        <group
            android:id="@+id/nav_g1"
            android:checkableBehavior="single">
            <item
                android:id="@+id/nav_1"
                android:icon="@drawable/ic_menu_share"
                android:title="@string/nav_1"/>
            <item
                android:id="@+id/nav_2"
                android:icon="@drawable/ic_menu_share"
                android:title="@string/nav_2"/>
        </group>
        <group
            android:id="@+id/nav_g2"
            android:checkableBehavior="single">
            <item
                android:id="@+id/nav_3"
                android:icon="@drawable/ic_menu_share"
                android:title="@string/nav_3"/>
            <item
                android:id="@+id/nav_4"
                android:icon="@drawable/ic_menu_share"
                android:title="@string/nav_4"/>
        </group>
    </group>
    <item android:title="Actions">
        <menu>
            <item
                android:id="@+id/nav_7"
                android:icon="@drawable/ic_menu_share"
                android:title="@string/nav_7"/>
            <item
                android:id="@+id/nav_8"
                android:icon="@drawable/ic_menu_share"
                android:title="@string/nav_8"/>
        </menu>
    </item>
</menu>

Remarques

  1. Comme mentionné dans cette réponse, chaque groupe doit avoir un identifiant unique pour afficher le diviseur.
  2. Selon cette réponse, les espaces correspondent aux spécifications de conception matérielle de Google.
  3. Avoir android:checkableBehavior="single"pour groupe parent est nécessaire pour que le problème de plusieurs éléments de menu sélectionnés dans cette réponse (mentionné dans les commentaires de hungryghost) ne se produise pas

Et voici la capture d'écran

Capture d'écran de l'écran de l'appareil

AaA
la source
5

Je voulais des séparateurs au-dessus du premier élément et après le dernier élément. En utilisant la solution @Nilesh, j'ai dû ajouter des éléments de menu factices et définir enabled sur false, ce qui me semblait vraiment sale. Et si je veux faire d'autres choses sympas dans mon menu?

J'ai remarqué que NavigationView étend FrameLayout afin que vous puissiez y mettre votre propre contenu comme vous le feriez pour un FrameLayout. J'ai ensuite défini un menu xml vide pour qu'il ne montre que ma mise en page personnalisée. Je comprends que cela va probablement à l'encontre de la voie que Google veut que nous prenions, mais si vous voulez un menu vraiment personnalisé, c'est un moyen facile de le faire.

<!--Note: NavigationView extends FrameLayout so we can put whatever we want in it.-->
<!--I don't set headerLayout since we can now put that in our custom content view-->
<android.support.design.widget.NavigationView
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_gravity="start"
    android:fitsSystemWindows="true"
    app:menu="@menu/empty_menu">

    <!--CUSTOM CONTENT-->
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <!-- CUSTOM HEADER -->
        <include
            android:id="@+id/vNavigationViewHeader"
            layout="@layout/navigation_view_header"/>

        <!--CUSTOM MENU-->
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:layout_below="@+id/vNavigationViewHeader">

            <View style="@style/NavigationViewLineSeperator"/>

            <Button android:text="Option 1"/>

            <View style="@style/NavigationViewLineSeperator"/>

            <Button android:text="Option 2"/>

            <View style="@style/NavigationViewLineSeperator"/>

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

Voici le style

<style name="NavigationViewLineSeperator">
        <item name="android:background">@drawable/line_seperator</item>
        <item name="android:layout_width">match_parent</item>
        <item name="android:layout_height">1dp</item>
</style>

Et dessinable

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">

    <solid android:color="@color/white"/>
    <size android:width="100sp"
          android:height="1sp" />
</shape>

Et le menu

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
</menu>

Éditer:

Au lieu de Buttons, vous pouvez utiliser TextView avec drawable qui imite l'apparence des éléments de menu d'origine:

 <TextView
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:text="@string/menu_support"
     android:drawableLeft="@drawable/menu_icon_support"
     style="@style/MainMenuText" />

// style.xml
<style name="MainMenuText">
    <item name="android:drawablePadding">12dp</item>
    <item name="android:padding">10dp</item>
    <item name="android:gravity">center_vertical</item>
    <item name="android:textColor">#fff</item>
</style>
Justin Fiedler
la source
1
merci, apparemment le moyen le plus pratique d'avoir des vues personnalisées comme éléments de menu
Jan Rabe
J'utilise cette solution aussi parce qu'elle me permet de définir plus facilement la police personnalisée des éléments et de changer la couleur du séparateur
luky
1

Le crédit devrait aller à Zorawar pour la solution, Désolé pour la duplication de la réponse, mais n'a pas pu ajouter autant de texte formaté dans un commentaire.

La solution de Zorawar fonctionne, le code pourrait être amélioré en tant que tel:

public void onNavigationItemSelected(int groupId) {

    //if an item from extras group is clicked,refresh NAV_ITEMS_MAIN to remove previously checked item
    navigationView.getMenu().setGroupCheckable(NAV_ITEMS_MAIN, (groupId == NAV_ITEMS_MAIN), true);
    navigationView.getMenu().setGroupCheckable(NAV_ITEMS_EXTRA, (groupId == NAV_ITEMS_EXTRA), true);


    //Update highlighted item in the navigation menu
    menuItem.setChecked(true);
}
Mushtaq Jameel
la source
qu'est-ce que NAV_ITEMS_MAIN et NAV_ITEMS_EXTRA et groupid ??
John
Ce sont des constantes pour le group_id
Mushtaq Jameel
0

La réponse de Nileh est juste, sauf qu'elle a un défaut de double vérification.

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">

    <group android:checkableBehavior="single" android:id="@+id/grp1">
        <item
            android:id="@+id/nav_register_customer"
            android:icon="@drawable/ic_menu_camera"
            android:checkableBehavior="none"
            android:title="Register Customer" />
    </group>
    <group  android:id="@+id/grp2"
        android:checkableBehavior="single"  >
        <item
            android:id="@+id/nav_slideshow"
            android:icon="@drawable/ic_menu_slideshow"
            android:checkableBehavior="none"
            android:title="Slideshow" />
    </group>
</menu>

Donc en utilisant

android: checkableBehavior = "single"

avec un identifiant unique résoudra le problème

Ajji
la source
0

Si vous souhaitez ajouter un diviseur de manière dynamique , vous pouvez simplement ajouter un sous-menu vide comme celui-ci:

Menu menu = navigationView.getMenu();
menu.addSubMenu(" ").add(" ");

cela ajoutera un diviseur.

assurez-vous simplement de passer le bon index lors de l'utilisation menu.getItem(int index)

Moh Mah
la source
0

En plus des réponses précédentes, si vous voulez des séparateurs décoratifs mais que vous ne voulez pas créer plusieurs groupes en raison de problèmes de «comportement vérifiable», vous pouvez attribuer le même identifiant de groupe à tous vos groupes.

Exemple:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group
    android:id="@+id/group_nav_common" <!-- New group id-->
    android:checkableBehavior="single">

    <item
        android:id="@+id/menu_item_nav_home"
        android:icon="@drawable/ic_home_black_24dp"
        android:title="@string/nav_menu_main" />
    <item
        android:id="@+id/menu_item_nav_articles"
        android:icon="@drawable/ic_art_track_black_24dp"
        android:title="@string/latest_news" />

    <item
        android:id="@+id/menu_item_nav_group_categories"
        android:title="@string/nav_menu_sections">
        <menu>
            <group
                android:id="@id/group_nav_common" <!-- Existing group id -->
                android:checkableBehavior="single">
                <!-- Programmatically populated section -->
            </group>
        </menu>
    </item>

    <item
        android:id="@+id/menu_item_nav_group_sites"
        android:title="@string/nav_menu_sites">
        <menu>
            <group
                android:id="@id/group_nav_common" <!-- Existing group id -->
                android:checkableBehavior="single">
                <item
                    android:id="@+id/menu_item_nav_select_site"
                    android:icon="@drawable/ic_account_balance_black_24dp"
                    android:title="@string/nav_menu_select_site" />
            </group>
        </menu>
    </item>
</group>

ievgen
la source
0

Si la réponse sélectionnée ne fonctionne pas pour vous, vous pouvez essayer de l'ajouter à onCreateOptionsMenuen plus de donner l'ID de groupe unique:

if (Build.VERSION.SDK_INT >= 28) {
    menu.setGroupDividerEnabled(true)
}
user806696
la source