¿Cómo crear un divisor simple en el nuevo NavigationView?


154

Google introdujo la NavigationViewversión 22.2.0 de la Biblioteca de soporte de diseño con la que puede crear un cajón muy fácilmente utilizando un recurso de menú.

¿Cómo puedo crear una línea divisoria simple entre dos elementos? Agrupar los artículos no funcionó. La creación de una sección de elementos secundarios crea una línea divisoria, pero requiere un título, que no quiero.

Cualquier ayuda sería apreciada.


Como se indicó en los comentarios, el problema con la respuesta aceptada es que el comportamiento comprobable no funciona en múltiples grupos (paralelos). Para evitar esto, no cree grupos paralelos, pero use submenús o subgrupos para obtener sus divisores como se describe en mi respuesta aquí: stackoverflow.com/questions/30766919/…
Hasta el

Respuestas:


319

Todo lo que necesita hacer es definir un groupcon una identificación única , he comprobado la implementación si el grupo tiene diferentes identificaciones, creará un divisor.

Ejemplo de menú, creando el separador:

<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
Me pregunto por qué esto (hasta donde yo sé) no está documentado. Creo que se preguntará mucho. ¡Gracias!
Gaëtan

16
El único problema con este enfoque es que setCheckedparece funcionar a nivel grupal. Si selecciona un elemento en el Grupo A, luego abra nuevamente el cajón y seleccione el elemento en el Grupo B, ambos elementos permanecerán resaltados. Quizás Google arregle este comportamiento en la próxima versión, pero por ahora, esa es la desventaja de usar múltiples grupos con NavigationView.
hungryghost

3
Excelente. Sobre el doble marcado, intente android:checkableBehavior="none"con su segundo grupo (supongo que son acciones, no navegación)
espinchi

12
Lo curioso es que si quitas la identificación del groupcompilador, se ejecutará pero los divisores están ocultos.
Vahid Amiri

55
Esto tampoco funciona para mí. Quería líneas entre los grupos de menú, no después de cada elemento.
Rich Morey

54

cree un drawer_item_bg.xml dibujable como este,

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

y agréguelo a NavigationView como aplicación: 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"/>

y aquí vamos...ingrese la descripción de la imagen aquí


1
esto funciona, pero también elimina el relleno izquierdo del ícono del elemento. al menos en mi código, no en su captura de pantalla por alguna razón
luky

@vbp Necesito el borde superior para el primer hijo, el borde inferior para otro hijo. ¿Cómo podría lograrlo? Es algo similar a la id. Primer niño en CSS
Prabs

@Prabs considera usar un fragmento, vista de reciclado o vistas personalizadas en lugar de NavigationView para una mejor personalización
vbp

1
Lo he hecho navMenuView.addItemDecoration(new DividerItemDecoration(NavigationViewActivity.this, DividerItemDecoration.VERTICAL));para el borde perfecto del artículo
Prabs

19

Simple agregar DeviderItemDecoration:

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

Se ve así:

ingrese la descripción de la imagen aquí


¿Puedo cambiar la altura de la addItemDecorationlínea a 1px?
Prabs

Gracias, tu solución funcionó para mí. Yo aprecio. Bro una pregunta más con esto. ¿Es posible eliminar el borde superior del primer elemento y establecer bordes solo en la parte inferior de los elementos?
víbora

@viper por favor refiérase a esto: bignerdranch.com/blog/…
SANAT

1
Ese tipo de divisor para cada artículo no sigue Material Guyidelines
Boris Ruzanov

19

Puede agregar divisores fácilmente configurando el Fondo del elemento del menú a través de XML usando 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"/>

Y use LayerDrawable como fondo. Conserva la superposición de ondas de diseño de material para 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>

El resultado:

ingrese la descripción de la imagen aquí


2
parece ser la mejor respuesta y ningún grupo involucrado
Michał Ziobro

¿Qué sucede si desea utilizar un color de fondo personalizado para el elemento seleccionado?
ataravati

Tengo un error en <forma>: el elemento no está permitido aquí
Sébastien REMY

11

Creo que tengo una solución aún mejor para el problema de múltiples elementos marcados. Utilizando mi manera, no tiene que preocuparse por cambiar su código al agregar nuevas secciones a su menú. Mi menú se parece a la solución aceptada escrita por Jared, con la diferencia de usar andoid: checkableBehavior = " all " en los grupos:

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

El checkableBehavior de 'all' hace posible marcar / desmarcar elementos individuales a voluntad, independientemente del grupo al que pertenecen. Solo tiene que almacenar el último elemento de menú marcado. El código java se ve así:

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

Hacer diferentes grupos, como la respuesta de Nilesh, hace un divisor entre ellos, pero crea el problema de dos elementos marcados en el cajón de navegación.

Una forma simple de cómo manejé esto fue:

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

Aún más simple:android:checkableBehavior="none"
espinchi

2
@espinchi: eso no funcionará si otros grupos contienen elementos del menú de navegación. Esta solución podría funcionar solo para acciones. No es una buena práctica de UX
Mushtaq Jameel

¡Excelente! Puede ser más claro si cambia sus constantes indefinidas NAV_ITEMS_MAIN y NAV_ITEMS_EXTRA con R.id.nav_items_group_main o R.id.nav_items_group_extra y agrega el XML requerido a su ejemplo
ChrisPrime

IS onNavigationItemSelected (menú final del menú menuItem) {Método predeterminado ?? ¿Dónde debo hacer este código?
John

y que es NAV_ITEMS_MAIN ??
John

8

No estoy seguro de si esto está arreglado API 26 (Android 8)o si fue posible todo el tiempo. Todavía soy un novato en la programación de Android. Sin embargo, agregué grupos de padres como a continuación. Pruebas en teléfonos físicos con Android 6,

  1. Tengo el divisor
  2. Seleccionar cualquier elemento, ya sea nav_g1o nav_g2se anule la selección de otros artículos.
  3. No se agregó relleno adicional debido a grupos anidados.
  4. No agregué ningún Javacódigo a los oyentes

Código de menú

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

Notas

  1. Como se menciona en esta respuesta, cada grupo debe tener una identificación única para mostrar el divisor.
  2. Según esta respuesta, los espacios coinciden con las especificaciones de diseño de material de Google.
  3. Se android:checkableBehavior="single"requiere tener un grupo principal para que el problema de múltiples elementos de menú seleccionados en esta respuesta (mencionado en los comentarios de hungryghost) no ocurra

Y aquí está la captura de pantalla.

Captura de pantalla de la pantalla del dispositivo.


5

Quería divisores sobre el primer artículo y después del último artículo. Usando la solución @Nilesh, tuve que agregar elementos de menú ficticios y establecer habilitado en falso, lo que me pareció realmente sucio. Además, ¿qué pasa si quiero hacer otras cosas interesantes en mi menú?

Noté que el NavigationView extiende FrameLayout para que pueda poner su propio contenido como lo haría para un FrameLayout. Luego configuro un menú vacío xml para que solo muestre mi diseño personalizado. Entiendo que esto probablemente va en contra del camino que Google quiere que tomemos, pero si desea un menú verdaderamente personalizado, esta es una manera fácil de hacerlo.

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

Aqui esta el estilo

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

Y dibujable

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

Y el menu

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

editar:

En lugar de botones, puede usar TextView con dibujable que imita el aspecto de los elementos del menú original:

 <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
gracias, aparentemente la forma más conveniente de tener vistas personalizadas como elementos del menú
Jan Rabe

También uso esta solución porque me permite configurar más fácilmente la fuente personalizada de los elementos y cambiar el color del divisor
luky

1

El crédito debe ir a Zorawar por la solución. Perdón por duplicar la respuesta pero no pudo agregar tanto texto formateado dentro de un comentario.

La solución de Zorawar funciona, el código podría mejorarse como tal:

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

¿Qué es NAV_ITEMS_MAIN y NAV_ITEMS_EXTRA y groupid?
John

Son constantes para el group_id
Mushtaq Jameel

0

La respuesta de Nileh es correcta, excepto que tiene una falla de verificación doble.

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

Entonces usando

android: checkableBehavior = "single"

con identificación única resolverá el problema


0

Si desea agregar un divisor dinámicamente , puede agregar un SubMenu vacío como este:

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

Esto agregará un divisor.

solo asegúrese de pasar el índice correcto cuando use menu.getItem(int index)


0

Además de las respuestas anteriores, si desea separadores decorativos pero no desea crear varios grupos debido a problemas de "comportamiento comprobable", puede asignar la misma identificación de grupo a todos sus grupos.

Ejemplo:

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

Si la respuesta seleccionada no funciona para usted, puede intentar agregar esto onCreateOptionsMenuademás de dar la identificación única del grupo:

if (Build.VERSION.SDK_INT >= 28) {
    menu.setGroupDividerEnabled(true)
}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.