如何取消选中导航视图中的选中项目?

How to uncheck checked items in Navigation View?

我知道可以通过在 onNavigationItemSelected 中调用 setCheckedItem() 或 return 真值来突出显示导航视图项目,以将项目显示为选定项目,但是如何取消选中导航视图的选中项?

这将取消选中项目:

    int size = mNavigationView.getMenu().size();
    for (int i = 0; i < size; i++) {
        mNavigationView.getMenu().getItem(i).setCheckable(false);
    }

我看到了@arsent 的解决方案并试了一下,它确实会做你想做的事,即取消select 所有项目...但是,我在下面遇到了问题场景:

  1. Select 菜单项 1(使用 NavigationView#setCheckedItem
  2. 根据@arsent 的解决方案取消select 所有项目
  3. 再次
  4. Select 菜单项 1(使用 NavigationView#setCheckedItem

在这种情况下,项目 1 不会被标记为已选中。这是因为导航视图在内部跟踪之前在步骤 1 中设置的 selected 项目,它在步骤 2 中没有改变,它只是跳过步骤 3,因为之前 selected 的项目是和我们现在 selecting 的一样。

为了避免这种情况,我的建议(和替代解决方案)只是拥有一个虚拟的不可见项目,并在您想要全部取消select 时使用 NavigationView#setCheckedItem 到 select 该项目,像这样

<item
    android:id="@+id/menu_none"
    android:title=""
    android:visible="false"/>

要取消select 一切都只是做

mNavigationView.setCheckedItem(R.id.menu_none);

Joao 的解决方案并没有完全符合我的预期。这将导致我的导航中未经检查的项目视图出现空白 space。

只需确保将视图设置为已消失:

<item
    android:id="@+id/your_menu_item_id_to_hide"
    android:title=""
    android:visible="false"/>


bottomNavigationView.getMenu().findItem(R.id.your_menu_item_id_to_hide).setChecked(true);
    bottomNavigationView.findViewById(R.id.your_menu_item_id_to_hide).setVisibility(View.GONE);

在这种情况下不需要 Arsent 解决方案。

要取消选中所有 MenuItems,包括 SubMenu 项,您必须使用递归 -

    private void unCheckAllMenuItems(@NonNull final Menu menu) {
        int size = menu.size();
        for (int i = 0; i < size; i++) {
            final MenuItem item = menu.getItem(i);
            if(item.hasSubMenu()) {
                // Un check sub menu items
                unCheckAllMenuItems(item.getSubMenu());
            } else {
                item.setChecked(false);
            }
        }
    }

调用上面的方法来取消选中所有项目,如下所示 -

unCheckAllMenuItems(navigationView.getMenu());

您需要做的就是像这样围绕您的小组:

 <group>
    <group
        android:id="@+id/grp1">
        <item
            android:id="@+id/nav_profile"
            android:icon="@drawable/ic_account_circle_24dp"
            android:title="@string/profile" />
    </group>
    <group
        android:id="@+id/grp2">
        <item
            android:id="@+id/nav_settings"
            android:icon="@drawable/ic_settings_24dp"
            android:title="@string/settings" />
        <item
            android:id="@+id/nav_help"
            android:icon="@drawable/topic_help"
            android:title="@string/help_feedback" />
    </group>
</group>

无需增加开销来循环菜单项!

我想像我这样的人就是这样使用这些方法的

public boolean onNavigationItemSelected(@NonNull MenuItem item) {
    switch (item.getItemId()) {
        case R.id.nav_today:
            break;
        case R.id.nav_calendar:
           navigationView.getMenu().performIdentifierAction(R.id.nav_today, 0);
           navigationView.getMenu().getItem(0).setChecked(true);//or
           navigationView.setCheckedItem(R.id.nav_today);//or
           drawerLayout.closeDrawers();
           break;
    }
    return true;
}

在您单击 R.id.nav_calendar 后尝试检查 R.id.nav_today,(顺便说一句:checkableBehavior="single"),不幸的是它不会工作。

那是因为在您的代码 navigationView.setCheckedItem(R.id.nav_today) 被调用后 R.id.nav_today 将立即被检查,但在此之后,您点击 R.id.nav_calendar 将自动检查。

这就是为什么您使用的任何方法似乎根本不起作用的原因。它正在工作,但会立即被覆盖。

引用@Codeversed,“无需循环菜单项,增加开销!”。但是,不需要创建多个组(在本例中他正在创建 @+id/grp1@+id/grp2)来取消选中先前选中的项目。

您可以使用 android:checkableBehavior 简单地为所有元素添加一个组,如下所示:

<group android:checkableBehavior="single">
    <item
        android:id="@+id/id1"
        android:checked="true"
        android:icon="@drawable/drawable1"
        android:title="@string/string1" />

    <item
        android:id="@+id/id2"
        android:icon="@drawable/drawable2"
        android:title="@string/string2" />
</group>

像这样让您的项目不可检查

<item
    android:id="@+id/profile_item"
    android:checkable="false"
    android:title="@string/profile"/>

我将@arsent 和@Rahul 的答案结合起来并编写了这段代码:

 private void NavigationView_NavigationItemSelected(object sender, NavigationView.NavigationItemSelectedEventArgs e)
        {
            var size = navigationView.Menu.Size();
            for (int i = 0; i < size; i++)
            {
               var item= navigationView.Menu.GetItem(i).SetChecked(false);
                if (item.HasSubMenu)
                {
                    for (int j = 0; j < item.SubMenu.Size(); j++)
                    {
                        item.SubMenu.GetItem(j).SetChecked(false);
                    }
                }
            }
                e.MenuItem.SetChecked(true);

            drawerLayout.CloseDrawers();

        }

以上代码适用于 xamarin c# 和工作,但您可以轻松转换为 java

要在 NavigationItemSelectedListener 中取消选中它,我必须使用 post(到 UI 线程):

App.getHandler().post(() -> menuItem.setChecked(false));

完整示例:

 NavigationView navigationView = findViewById(R.id.nav_view);
        navigationView.setNavigationItemSelectedListener(
                menuItem -> {
                    menuItem.setChecked(true);

                    mDrawerLayout.closeDrawers();

                    switch (menuItem.getItemId()) {
                        ...
                    }

                    App.getHandler().post(() -> menuItem.setChecked(false));

                    return true;
                });

p.s。在我的例子中 App.getHandler() returns Handler UI Thread Lopper

的实例

我不得不结合使用这里提到的所有解决方案。在我的例子中,我想在单击项目时打开一个 URL Intent(打开浏览器)。单击后应取消选中单击的项目并重置为之前的项目。重要的是要理解,您不能在点击侦听器事件期间取消选中某个项目,因为选中状态将在之后处理。所以这是我在 Kotlin 中的解决方案:

        val item = navigationView.menu.findItem(R.id.menu_item)
        item.setOnMenuItemClickListener {

            val oldItem = navigationView.checkedItem
            rootView.postDelayed({ // you can use here any View to post a Runnable with a delay
                navigationView.setCheckedItem(oldItem?.itemId ?: R.id.default_item)
            }, 500)
            browseURL("https://www.example.com")
            true
        }

我用的是Navigation Drawer in combination with the Jetpack Navigation.

@arsent 的回答是正确的,但是 setCheckable(false) 取消选中所有项目,它防止将来检查这些项目。

只需使用 setChecked(false)

  int size = mNavigationView.getMenu().size();

    for (int i = 0; i < size; i++) {
        mNavigationView.getMenu().getItem(i).setChecked(false);
    }