Como criar um divisor simples no novo NavigationView?

154

O Google introduziu NavigationViewna Biblioteca de suporte de design versão 22.2.0, com a qual você pode criar uma gaveta com muita facilidade usando um recurso de menu.

Como posso criar uma linha divisória simples entre dois itens? O agrupamento dos itens não funcionou. Criar uma seção de subitens cria uma linha divisória, mas requer um título, que eu não quero.

Qualquer ajuda seria apreciada.

Longi
fonte
Conforme declarado nos comentários, o problema com a resposta aceita é que o comportamento verificável não funciona em vários grupos (paralelos). Para evitar isso, não crie grupos paralelos, mas use submenus ou subgrupos para obter seus divisores, conforme descrito na minha resposta aqui: stackoverflow.com/questions/30766919/…
Até

Respostas:

319

Tudo o que você precisa fazer é definir um groupcom um ID exclusivo . Verifiquei a implementação. Se o grupo tiver IDs diferentes, ele criará um divisor.

Exemplo de menu, criando o 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>
NJ
fonte
9
Me pergunto por que isso (até onde eu sei) não está documentado. Eu acho que isso será muito solicitado. Obrigado!
Gaëtan
16
O único problema com essa abordagem é que setCheckedparece funcionar no nível do grupo. Se você selecionar um item no Grupo A, abra a gaveta novamente e selecione o item no Grupo B, os dois itens permanecerão destacados. Talvez o Google conserte esse comportamento no próximo lançamento, mas, por enquanto, essa é a desvantagem do uso de vários grupos com o NavigationView.
hungryghost
3
Ótimo. Sobre o dobro verificado, tente android:checkableBehavior="none"para o seu segundo grupo (que são ações, não de navegação, presumo)
espinchi
12
O engraçado é que, se você remover o ID, groupele será compilado e executado, mas os divisores estarão ocultos.
Vahid Amiri 8/16
5
Isso também não funciona para mim. Eu queria linhas entre os grupos de menus, não depois de cada item.
Ricos Morey
54

crie um drawer_item_bg.xml 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>

e adicione-o ao NavigationView como aplicativo: 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 aqui vamos nós...insira a descrição da imagem aqui

vbp
fonte
1
isso funciona, mas também remove o preenchimento esquerdo do ícone do item. pelo menos no meu código, não em sua imagem, por algum motivo
luky
@vbp Preciso da borda superior do primeiro filho e da borda inferior do outro filho. Como eu pude alcançar. É algo semelhante a criança id.first em css
Prabs
@Prabs considerar o uso de um fragmento, recyclerview ou personalizados vistas em vez de NavigationView para uma melhor personalização
vbp
1
Eu fiz navMenuView.addItemDecoration(new DividerItemDecoration(NavigationViewActivity.this, DividerItemDecoration.VERTICAL));para a beira item perfeito
Prabs
19

Simples adicione DeviderItemDecoration:

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

É assim:

insira a descrição da imagem aqui

SANAT
fonte
Posso alterar a altura da addItemDecorationlinha para 1px?
Prabs
Obrigado, sua solução funcionou para mim. Eu aprecio. Bro mais uma pergunta com isso. É possível remover a borda superior do primeiro item e definir bordas apenas na parte inferior dos itens?
víbora
@viper consulte: bignerdranch.com/blog/…
SANAT
1
Esse tipo de divisor para cada item não segue as Orientações Materiais
Boris Ruzanov 26/04/19
19

Você pode adicionar divisores facilmente, definindo o plano de fundo do item de menu via 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"/>

E use LayerDrawable como plano de fundo. Ele preserva a sobreposição de ondulação do design do material por cliques.

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

O resultado:

insira a descrição da imagem aqui

Stanislav Perchenko
fonte
2
parece ser a melhor resposta e nenhum grupo envolvido
Michał Ziobro
E se você quiser usar uma cor de fundo personalizada para o item selecionado?
Ataravati 17/07/19
Estou com um erro no <shape>: o elemento não é permitido aqui
Sébastien REMY
11

Eu acho que tenho uma solução ainda melhor para o problema de vários itens verificados. Usando o meu jeito, você não precisa se preocupar em alterar seu código ao adicionar novas seções ao seu menu. Meu menu se parece com a solução aceita, escrita por Jared, com a diferença de usar andoid: checkableBehavior = " all " nos 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>

O checkableBehavior de 'all' torna possível marcar / desmarcar itens únicos à vontade, independentemente de qual grupo eles pertencem. Você só precisa armazenar o último menu marcado. O código java fica assim:

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;
}
plexo
fonte
8

Fazer grupos diferentes, como a resposta de Nilesh, cria um divisor no meio, mas cria o problema de dois itens marcados na gaveta de navegação.

Uma maneira simples de como eu lidei com isso foi:

    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
fonte
Ainda mais simples:android:checkableBehavior="none"
espinchi
2
@espinchi - Isso não funcionará se outros grupos contiverem itens de menu de navegação. Esta solução pode funcionar apenas para ações. Não boa prática UX
Mushtaq Jameel
Excelente! Pode ser mais clara se você mudou suas constantes indefinidos NAV_ITEMS_MAIN e NAV_ITEMS_EXTRA com R.id.nav_items_group_main ou R.id.nav_items_group_extra e adicionar o XML necessário para o seu exemplo
ChrisPrime
IS onNavigationItemSelected (final MenuItem menuItem) {Método padrão ?? onde devo fazer esse código?
John
e o que é NAV_ITEMS_MAIN ??
John
8

Não tenho certeza se isso está corrigido API 26 (Android 8)ou era possível o tempo todo. Eu ainda sou um noob na programação Android. No entanto, adicionei grupos de pais como abaixo. Testando no telefone físico Android 6,

  1. Eu tenho o divisor
  2. Selecionando qualquer item de nav_g1ounav_g2 desmarcará outros itens.
  3. Nenhum preenchimento extra foi adicionado devido a grupos aninhados.
  4. Não adicionei nenhum Javacódigo aos ouvintes

Código do 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>

Notas

  1. Como mencionado neste resposta, cada grupo precisa ter um ID exclusivo para mostrar o divisor.
  2. De acordo com essa resposta, os espaços correspondem às especificações de design do material do google.
  3. android:checkableBehavior="single"É necessário ter um grupo de pais para que o problema de vários itens de menu selecionados nesta resposta (mencionado nos comentários por hungryghost) não aconteça

E aqui está a captura de tela

Captura de tela da tela do dispositivo

AaA
fonte
5

Eu queria divisórias acima do primeiro item e depois do último item. Usando a solução @Nilesh, eu tive que adicionar itens de menu fictícios e definir ativado como false, o que parecia muito sujo. Além disso, e se eu quiser fazer outras coisas legais no meu menu?

Notei que o NavigationView estende o FrameLayout para que você possa colocar seu próprio conteúdo como faria para um FrameLayout. Em seguida, defino um xml de menu vazio para que ele mostre apenas meu layout personalizado. Entendo que isso provavelmente vai contra o caminho que o Google quer que tomemos, mas se você quiser um menu verdadeiramente personalizado, é uma maneira fácil de fazê-lo.

<!--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 está o 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>

E drawable

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

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

editar:

Em vez de botões, você pode usar o TextView com drawable, que imita os itens de menu originais:

 <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
fonte
1
graças, aparentemente, a maneira mais conveniente de ter vistas personalizadas como itens de menu
Jan Rabe
i usar esta solução também porque me permite conjunto mais fácil a fonte personalizada de itens e mudar a cor divisor
luky
1

O crédito deve ser enviado à Zorawar pela solução. Desculpe por duplicar a resposta, mas não foi possível adicionar tanto texto formatado em um comentário.

A solução da Zorawar funciona, o código pode ser aprimorado da seguinte forma:

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
fonte
o que é NAV_ITEMS_MAIN e NAV_ITEMS_EXTRA e groupid ??
John
São constantes para o group_id
Mushtaq Jameel 25/09
0

A resposta de Nileh está certa, exceto que há uma falha de verificação dupla.

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

Então, usando

android: checkableBehavior = "single"

com id exclusivo resolverá o problema

Ajji
fonte
0

Se você deseja adicionar divisores dinamicamente , basta adicionar um submenu vazio como este:

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

isso adicionará um divisor.

apenas certifique-se de passar o índice correto ao usar menu.getItem(int index)

Moh Mah
fonte
0

Além das respostas anteriores, se você deseja separadores decorativos, mas não deseja criar vários grupos devido a problemas de "comportamento verificável" - é possível atribuir o mesmo ID de grupo a todos os seus grupos.

Exemplo:

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

Se a resposta selecionada não funcionar para você, tente adicionar isso onCreateOptionsMenualém de fornecer o ID do grupo exclusivo:

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