Как создать простой разделитель в новом NavigationView?


154

Google представил NavigationViewв Библиотеке поддержки дизайна версию 22.2.0, с помощью которой вы можете очень легко создать ящик, используя ресурс меню.

Как я могу создать простую разделительную линию между двумя элементами? Группировка предметов не сработала. Создание раздела подэлементов создает разделительную линию, но требует заголовка, который мне не нужен.

Любая помощь будет оценена.


Как указано в комментариях к нему, проблема с принятым ответом заключается в том, что проверяемое поведение не работает в нескольких (параллельных) группах. Чтобы избежать этого, не создавайте параллельные группы, но используйте подменю или подгруппы, чтобы получить разделители, как описано в моем ответе здесь: stackoverflow.com/questions/30766919/…
до

Ответы:


319

Все, что вам нужно сделать, это определить groupс уникальным идентификатором. Я проверил реализацию, если группа имеет разные идентификаторы, это создаст разделитель.

Пример меню, создающего разделитель:

<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
Интересно, почему это (насколько я знаю) не задокументировано. Я думаю, об этом будет много спросить. Спасибо!
Гаэтан

16
Единственная проблема этого подхода заключается в том setChecked, что он работает на уровне группы. Если вы выберите элемент в группе A, затем снова откройте ящик и выберите элемент в группе B, оба элемента останутся выделенными. Возможно, Google исправит это поведение в следующем выпуске, но сейчас это недостаток использования нескольких групп с NavigationView.
Hungryghost

3
Отлично. Насчет двойной проверки, попробуйте android:checkableBehavior="none"для вашей второй группы (это действия, а не навигация, я полагаю)
espinchi

12
Забавно, если вы удалите идентификатор из groupнего, он будет скомпилирован и запущен, но разделители скрыты.
Вахид Амири

5
Это не работает для меня тоже. Я хотел строки между группами меню, а не после каждого пункта.
Рич Мори

54

создайте drawableite_itm_bg.xml вот так,

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

и добавьте его в NavigationView как приложение: itemBackground = "@ drawable / box_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"/>

и здесь мы идем...введите описание изображения здесь


1
это работает, но также удаляет левый отступ значка элемента. по крайней мере, в моем коде, а не на вашем скриншоте по какой-то причине
Luk

@vbp Мне нужна верхняя граница для первого ребенка, нижняя граница для другого ребенка. Как я мог достичь. Это что-то похожее на id.first child в css
Prabs

@Prabs рассматривает возможность использования фрагмента, повторного просмотра или пользовательских представлений вместо NavigationView для лучшей настройки
vbp

1
Я сделал navMenuView.addItemDecoration(new DividerItemDecoration(NavigationViewActivity.this, DividerItemDecoration.VERTICAL));для идеальной границы предмета
Prabs

19

Просто добавьте DeviderItemDecoration:

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

Это выглядит так:

введите описание изображения здесь


Могу ли я изменить высоту addItemDecorationлинии до 1px?
Прабс

Спасибо, ваше решение сработало для меня. Я ценю. Братан, еще один вопрос с этим. Можно ли удалить верхнюю границу для первого элемента и установить границы только для нижних элементов?
Гадюка

@viper, пожалуйста, отсылайте это: bignerdranch.com/blog/…
SANAT

1
Такого рода разделители для каждого элемента не следуют Материальным ориентирам
Борис Рузанов

19

Вы можете легко добавить разделители, установив фон меню с помощью XML, используя 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"/>

И используйте LayerDrawable в качестве фона. Это сохраняет дизайн материала наложения пульсаций для кликов.

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

Результат:

введите описание изображения здесь


2
кажется лучшим ответом, и никакая группа не вовлечена
Michał Ziobro

Что если вы хотите использовать собственный цвет фона для выбранного элемента?
Атаравати

У меня есть ошибка в <shape>: элемент здесь не разрешен
Себастьян

11

Я думаю, что у меня есть еще лучшее решение проблемы нескольких проверенных пунктов. Используя мой способ, вам не нужно беспокоиться об изменении кода при добавлении новых разделов в ваше меню. Мое меню выглядит так же, как принятое решение, написанное Джаредом, с разницей в использовании andoid: checkableBehavior = " all " для групп:

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

CheckableBehavior 'all' позволяет проверять / снимать флажки с отдельных элементов по желанию, независимо от того, к какой группе они принадлежат. Вам просто нужно сохранить последний проверенный пункт меню. Java-код выглядит так:

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

Создание разных групп, таких как ответ Нилеша, делает разделитель между ними, но создает проблему двух проверенных элементов в навигационном ящике.

Простой способ, как я справился с этим, был:

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

Еще проще:android:checkableBehavior="none"
Эспинчи

2
@espinchi - Это не будет работать, если другие группы содержат пункты меню навигации. Это решение может работать только для действий. Не хорошая практика UX
Mushtaq Jameel

Превосходно! Это может быть понятнее, если вы изменили свои неопределенные константы NAV_ITEMS_MAIN и NAV_ITEMS_EXTRA с помощью R.id.nav_items_group_main или R.id.nav_items_group_extra и добавили требуемый XML в ваш пример
ChrisPrime

ISNavigationItemSelected (окончательный MenuItem menuItem) {Метод по умолчанию ?? где я должен сделать этот код?
Джон

а что такое NAV_ITEMS_MAIN ??
Джон

8

Я не уверен, исправлено API 26 (Android 8)ли это или это было возможно все время. Я все еще новичок в программировании Android. Однако я добавил родительские группы, как показано ниже. Тестирование на физическом телефоне Android 6,

  1. У меня есть делитель
  2. Выбор любого элемента из одного nav_g1или nav_g2отменяет выбор других элементов.
  3. Никаких дополнительных отступов не добавлено из-за вложенных групп.
  4. Я не добавил Javaкод для слушателей

Код меню

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

Ноты

  1. Как упоминалось в этом ответе, каждая группа должна иметь уникальный идентификатор, чтобы показать разделитель.
  2. Согласно этому ответу места соответствуют спецификации дизайна материала Google.
  3. Наличие android:checkableBehavior="single"родительской группы является обязательным, поэтому проблема нескольких выбранных пунктов меню в этом ответе (упомянутых в комментариях Hungryghost) не возникает

И вот скриншот

Скриншот экрана устройства


5

Я хотел разделители над первым пунктом и после последнего элемента. Используя решение @Nilesh, я должен был добавить фиктивные пункты меню и установить значение false, что было очень грязно. Плюс, что если я захочу сделать другие интересные вещи в моем меню?

Я заметил, что NavigationView расширяет FrameLayout, так что вы можете поместить в него свой собственный контент, как если бы вы использовали FrameLayout. Затем я установил пустое меню xml, чтобы оно показывало только мой пользовательский макет. Я понимаю, что это, вероятно, идет вразрез с тем, как Google хочет, чтобы мы пошли по нему, но если вы хотите действительно индивидуальное меню, это простой способ сделать это.

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

Вот стиль

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

И рисовать

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

И меню

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

редактировать:

Вместо кнопок вы можете использовать TextView с drawable, который имитирует внешний вид оригинальных пунктов меню:

 <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
спасибо, по-видимому, самый удобный способ иметь пользовательские представления в качестве пунктов меню
Jan Rabe

Я использую это решение также потому, что оно позволяет мне более легко установить собственный шрифт элементов и изменить цвет разделителя
luky

1

Автор должен отдать должное Zorawar за решение, извините за дублирование ответа, но не смог добавить столько отформатированного текста в комментарии.

Решение Zorawar работает, код может быть улучшен как таковой:

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

что такое NAV_ITEMS_MAIN и NAV_ITEMS_EXTRA и идентификатор группы ??
Джон

Они являются константами для group_id
Муштак Джамиль

0

Ответ Ниле верен, за исключением того, что у него есть один недостаток двойной проверки.

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

Итак, используя

андроид: checkableBehavior = "сингл"

с уникальным идентификатором решит проблему


0

Если вы хотите добавить разделитель динамически , вы можете просто добавить пустое SubMenu следующим образом:

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

это добавит разделитель.

просто обязательно передайте правильный индекс при использовании menu.getItem(int index)


0

В дополнение к предыдущим ответам, если вы хотите использовать декоративные разделители, но не хотите создавать несколько групп из-за проблем с «проверяемым поведением», вы можете назначить один и тот же идентификатор группы всем своим группам.

Пример:

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

Если выбранный ответ не работает для вас, вы можете попробовать добавить его onCreateOptionsMenuв дополнение, чтобы дать уникальный идентификатор группы:

if (Build.VERSION.SDK_INT >= 28) {
    menu.setGroupDividerEnabled(true)
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.