Как установить общее проверяемое поведение для всех групп в NavigationView?


Я создал две группы с уникальными идентификаторами (мне нужен разделитель), и они оба имеют checkableBehavior Набор single. Это позволяет проверять сразу несколько элементов из разных групп, и именно этого я стараюсь избегать. Я бы хотел, чтобы один пункт был проверен по максимуму, во всех группах.

Поскольку я не нашел способа сделать это в XML, я попытался реализовать простую логику в onNavigationItemSelected, чтобы снять галочку с предыдущего пункта меню:

if (previousItem != null)
   previousItem.setChecked(false);
currentItem.setChecked(true);

Но setChecked(false) метод никогда не работал для меня - товар остается проверенным.

Вот мой пример кода:

Menu_navigation.xml:

<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group
        android:id="@+id/nav_group_1"
        android:checkableBehavior="single">
    <item
            android:id="@+id/nav_feed"
            android:title="@string/feed"/>
    <item
            android:id="@+id/nav_people"
            android:title="@string/people"/>
</group>
<group
        android:id="@+id/nav_group_2"
        android:checkableBehavior="single">
    <item
            android:id="@+id/nav_settings"
            android:title="@string/settings"/>
    <item
            android:id="@+id/nav_help_feedback"
            android:title="@string/help_feedback"/>
    <item
            android:id="@+id/nav_logout"
            android:title="@string/logout"/>
</group>

NavigationItemSelectedListener:

 mUiNavigationView.setNavigationItemSelectedListener(
                new NavigationView.OnNavigationItemSelectedListener() {
                    @Override
                    public boolean onNavigationItemSelected(MenuItem menuItem) {
                        if (previousItem != null)
                           previousItem.setChecked(false);
                        currentItem.setChecked(true);
                        //...
                        changeCurrentFragment(...);
                        return true;
                    }
                });

Мне нужна подсказка! Спасибо.

6 29

6 ответов:

Вот решение.

Шаг 1: Удалить

android:checkableBehavior="single"

Из обеих групп.

Шаг 2: Добавьте слушателю следующую логику:
mUiNavigationView.setNavigationItemSelectedListener(
            new NavigationView.OnNavigationItemSelectedListener() {
                @Override
                public boolean onNavigationItemSelected(MenuItem menuItem) {
                    menuItem.setCheckable(true);
                    menuItem.setChecked(true);
                    if (mPreviousMenuItem != null) {
                        mPreviousMenuItem.setChecked(false);
                    }
                    mPreviousMenuItem = menuItem;
                    //...
                    changeCurrentFragment(...);
                    return true;
                }
            });

Примечание: вместо вызова menuItem.setCheckable(true) можно задать android:checkable="true" для каждого элемента в XML.

Решение@Moinkhan должно работать так же (спасибо, upvoted), но я не хотел перебирать пункты меню каждый раз, когда выбирается новая позиция.

На самом деле, вам не нужны отдельные параллельные группы для разделителей. Вы можете собрать все в одну группу и поместить в нее подменю (есть названия) или подгруппы (нет названия). Там будут разделители для этих подменю и подгрупп. Таким образом, проверяемое поведение работает без обходного пути. (к вашему сведению: это на Либ поддержки дизайна 23.1.1)

Меню с разделителями

<group
    android:id="@+id/drawer_group"
    android:checkableBehavior="single">
    <item
        android:id="@+id/nav_1"
        android:title="Menu1" />
    <item
        android:id="@+id/nav_2"
        android:title="Menu2" />
    <item
        android:id="@+id/nav_3"
        android:title="Menu3" />
    <item
        android:id="@+id/nav_4"
        android:title="Menu4" />

    <item
        android:id="@+id/drawer_submenu"
        android:title="Subheader">
        <menu>
            <group android:checkableBehavior="single">
                <item
                    android:id="@+id/nav_sub1_1"
                    android:title="Menu_Sub1_1" />
                <item
                    android:id="@+id/nav_sub1_2"
                    android:title="Menu_Sub1_2" />
            </group>
        </menu>
    </item>

    <group android:id="@+id/drawer_subgroup">
        <item
            android:id="@+id/nav_subgroup_item"
            android:title="Menu_Sub2_2" />
    </group>
</group>

В коде я просто делаю следующее, и одиночная проверка работает как ожидается:

@Override
public boolean onNavigationItemSelected(MenuItem item) {
    mNavigationView.setCheckedItem(item.getItemId());
    ...
}

Не нужно удалять checkableBehavior="single", просто используйте

navigationView.setCheckedItem(item.getItemId());

Вместо item.setChecked(true).

Хорошо, я нашел решение .. просто добавьте этот фрагмент кода в onNavigationItemSelected Метод

@Override
    public boolean onNavigationItemSelected(MenuItem menuItem) {
    Menu m = navView.getMenu();
    for (int i=0;i<m.size();i++) {
        MenuItem mi = m.getItem(i);
        if (!(mi.getItemId() == menuItem.getItemId())) {
            mi.setCheckable(false);
        }
    }
    menuItem.setCheckable(true);
    menuItem.setChecked(true);
    return false;
}

Вот и все .. И да setChecked (false) не работает. Просто потому, что из списка меню должен быть один единственный пункт, который должен быть проверен. Таким образом, вы можете снять его только при выборе другого элемента .. И если вы нажмете на выбранный элемент, navigationview никогда не снимет его флажок. Просто потому, что сценарий я уже объяснил.

В реализации NavigationView есть ошибка аннулирования, но вам не нужно использовать setCheckable(), вам просто нужно аннулировать NavigationView после вызова setChecked(false), например:

    previousItem.setChecked(false);
    navigationView.invalidate();

Однако группа меню не должна иметь checkableBehavior="single", потому что в исключительном режиме вызов setChecked(boolean) на MenuItem в группе установит этот пункт как проверенный, передаете ли вы true или false. Таким образом, чтобы setChecked(false) работал, вы должны удалить checkableBehavior="single" из ваших определений меню.

Я создал проблему об этом здесь: https://code.google.com/p/android/issues/detail?id=178709

Вот простое и милое решение, которое я опубликовал здесь:)

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

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

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

}