Come creare un semplice divisore nel nuovo NavigationView?


154

Google ha introdotto NavigationViewnella Design Support Library versione 22.2.0 con la quale è possibile creare un cassetto molto facilmente utilizzando una risorsa di menu.

Come posso creare una semplice linea di divisione tra due elementi? Il raggruppamento degli articoli non ha funzionato. La creazione di una sezione degli elementi secondari crea una linea di divisione, ma richiede un titolo, che non voglio.

Qualsiasi aiuto sarebbe apprezzato.


Come indicato nei commenti, il problema con la risposta accettata è che il comportamento verificabile non funziona su più gruppi (paralleli). Per evitarlo, non creare gruppi paralleli, ma utilizzare sottomenu o sottogruppi per ottenere i divisori come descritto nella mia risposta qui: stackoverflow.com/questions/30766919/…
Fino al

Risposte:


319

Tutto quello che devi fare è definire un groupcon un ID univoco , ho verificato l'implementazione se il gruppo ha ID diversi creerà un divisore.

Menu di esempio, creando il separatore:

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

9
Mi chiedo perché questo (per quanto ne so) non sia documentato. Penso che sarà chiesto molto. Grazie!
Gaëtan,

16
L'unico problema con questo approccio è che setCheckedsembra funzionare a livello di gruppo. Se si seleziona un elemento nel gruppo A, quindi si apre nuovamente il cassetto e si seleziona l'elemento nel gruppo B, entrambi gli elementi rimarranno evidenziati. Forse Google risolverà questo comportamento nella prossima versione, ma per ora, questo è l'aspetto negativo dell'utilizzo di più gruppi con NavigationView.
hungryghost

3
Grande. A proposito del doppio controllo, prova android:checkableBehavior="none"per il tuo secondo gruppo (che sono azioni, non navigazione, presumo)
espinchi

12
Cosa divertente, se rimuovi l'ID da groupesso verrà compilato ed eseguito ma i divisori sono nascosti.
Vahid Amiri,

5
Questo non funziona neanche per me. Volevo linee tra i gruppi di menu, non dopo ogni elemento.
Rich Morey,

54

crea un drawer_item_bg.xml estraibile come questo,

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

e aggiungilo a NavigationView come app: itemBackground = "@ drawable / drawer_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"/>

e qui andiamo ...inserisci qui la descrizione dell'immagine


1
funziona, ma rimuove anche l'imbottitura sinistra dell'icona dell'oggetto. almeno nel mio codice, non nel tuo screenshot per qualche motivo
luky

@vbp Ho bisogno del bordo superiore per il primo figlio, il bordo inferiore per l'altro figlio. Come ho potuto raggiungere. È qualcosa di simile a id. First child in css
Prabs,

@Prabs considera l'utilizzo di un frammento, di una vista recyclerview o personalizzata invece di NavigationView per una migliore personalizzazione
vbp

1
Ho fatto navMenuView.addItemDecoration(new DividerItemDecoration(NavigationViewActivity.this, DividerItemDecoration.VERTICAL));per il bordo dell'oggetto perfetto
Prabs il

19

Semplice aggiungere DeviderItemDecoration:

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

Sembra così:

inserisci qui la descrizione dell'immagine


Posso modificare l'altezza della addItemDecorationlinea su 1px?
Prabs,

Grazie la tua soluzione ha funzionato per me. Apprezzo. Bro un'altra domanda con questo. È possibile rimuovere il bordo superiore per il primo elemento e impostare i bordi solo sul fondo degli elementi?
vipera

@viper si prega di fare riferimento a questo: bignerdranch.com/blog/…
SANAT

1
Quel tipo di divisore per ogni articolo non segue Material Guyidelines
Boris Ruzanov,

19

È possibile aggiungere facilmente divisori impostando Sfondo elemento di menu tramite XML utilizzando 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"/>

E usare LayerDrawable come sfondo. Conserva la sovrapposizione dell'ondulazione del disegno materiale per i clic.

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

Il risultato:

inserisci qui la descrizione dell'immagine


2
sembra essere la risposta migliore e nessun gruppo coinvolto
Michał Ziobro,

Cosa succede se si desidera utilizzare un colore di sfondo personalizzato per l'elemento selezionato?
Ataravati,

Ho un errore su <shape>: l'elemento non è consentito qui
Sébastien REMY

11

Penso di avere una soluzione ancora migliore per il problema di più elementi controllati. A modo mio non devi preoccuparti di cambiare il codice quando aggiungi nuove sezioni al tuo menu. Il mio menu sembra proprio la soluzione accettata scritta da Jared, con la differenza di usare andoid: checkableBehavior = " all " sui gruppi:

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

Il comportamento checkable di 'all' consente di selezionare / deselezionare singoli elementi a piacimento, indipendentemente dal gruppo a cui appartengono. Devi solo memorizzare l'ultimo menu selezionato. Il codice java è simile al seguente:

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

8

Creare gruppi diversi come la risposta di Nilesh crea un divisore tra Ma crea il problema di due elementi controllati nel cassetto di navigazione.

Un modo semplice in cui ho gestito questo è stato:

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

Ancora più semplice:android:checkableBehavior="none"
espinchi il

2
@espinchi - Non funzionerà se altri gruppi contengono voci del menu di navigazione. Questa soluzione potrebbe funzionare solo per azioni. Non buona pratica UX
Mushtaq Jameel,

Eccellente! Potrebbe essere più chiaro se hai cambiato le costanti indefinite NAV_ITEMS_MAIN e NAV_ITEMS_EXTRA con R.id.nav_items_group_main o R.id.nav_items_group_extra e hai aggiunto il codice XML richiesto al tuo esempio
ChrisPrime

IS onNavigationItemSelected (final MenuItem menuItem) {Metodo predefinito ?? dove dovrei fare questo codice?
Giovanni,

e cos'è NAV_ITEMS_MAIN ??
Giovanni,

8

Non sono sicuro se questo è stato risolto API 26 (Android 8)o è stato possibile tutto il tempo. Sono ancora un noob nella programmazione Android. Tuttavia ho aggiunto i gruppi di genitori come di seguito. Test su telefono fisico Android 6,

  1. Ho il divisore
  2. Selezionando qualsiasi elemento da uno nav_g1o nav_g2deselezionerai altri elementi.
  3. Nessuna imbottitura aggiuntiva aggiunta a causa di gruppi nidificati.
  4. Non ho aggiunto alcun Javacodice agli ascoltatori

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

Appunti

  1. Come accennato in questo risposta, ogni gruppo deve avere un ID univoco per mostrare il divisore.
  2. Secondo questa risposta gli spazi corrispondono alle specifiche di progettazione del materiale di Google.
  3. Avendo android:checkableBehavior="single"per il gruppo genitore è richiesto quindi il problema di più voci di menu selezionate in questa risposta (citato nei commenti da hungryghost) non avviene

Ed ecco lo screenshot

Schermata della schermata del dispositivo


5

Volevo divisori sopra il primo elemento e dopo l'ultimo elemento. Usando la soluzione @Nilesh ho dovuto aggiungere voci di menu fittizie e impostare abilitato su false che sembrava davvero sporco. Inoltre cosa succede se voglio fare altre cose interessanti nel mio menu?

Ho notato che NavigationView estende FrameLayout in modo da poter inserire i tuoi contenuti proprio come faresti per un FrameLayout. Ho quindi impostato un menu XML vuoto in modo che mostri solo il mio layout personalizzato. Capisco che questo probabilmente va contro il percorso che Google vuole che prendiamo, ma se vuoi un menu veramente personalizzato questo è un modo semplice per farlo.

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

Ecco lo stile

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

E disegnabile

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

E il menu

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

modificare:

Invece di Pulsanti puoi usare TextView con un disegno che imita l'aspetto delle voci di menu originali:

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

1
grazie, apparentemente il modo più conveniente di avere viste personalizzate come voci di menu
Jan Rabe,

io uso questa soluzione anche perché mi permette di impostare più facilmente il carattere personalizzato degli elementi e cambiare il colore del divisore
luky

1

Ringraziamo Zorawar per la soluzione, mi spiace per aver duplicato la risposta ma non ho potuto aggiungere così tanto testo formattato all'interno di un commento.

La soluzione di Zorawar funziona, il codice potrebbe essere migliorato come tale:

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

cos'è NAV_ITEMS_MAIN e NAV_ITEMS_EXTRA e groupid ??
Giovanni,

Sono costanti per il group_id
Mushtaq Jameel,

0

La risposta di Nileh è giusta, tranne per il fatto che ha un difetto di doppio controllo.

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

Quindi usando

Android: checkableBehavior = "single"

con ID univoco deve risolvere il problema


0

Se vuoi aggiungere il divisore in modo dinamico , puoi semplicemente aggiungere un Sottomenu vuoto come questo:

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

questo aggiungerà un divisore.

assicurati di passare l'indice giusto quando lo usi menu.getItem(int index)


0

Oltre alle risposte precedenti se si desidera separatori decorativi ma non si desidera creare più gruppi a causa di problemi di "comportamento verificabile", è possibile assegnare lo stesso ID di gruppo a tutti i gruppi.

Esempio:

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


0

Se la risposta selezionata non funziona per te, potresti provare ad aggiungerla onCreateOptionsMenuoltre a fornire l'ID univoco del gruppo:

if (Build.VERSION.SDK_INT >= 28) {
    menu.setGroupDividerEnabled(true)
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.