如何取消选中导航视图中的选中项目?
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 所有项目...但是,我在下面遇到了问题场景:
- Select 菜单项 1(使用
NavigationView#setCheckedItem
)
- 根据@arsent 的解决方案取消select 所有项目
再次 - 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);
}
我知道可以通过在 onNavigationItemSelected
中调用 setCheckedItem()
或 return 真值来突出显示导航视图项目,以将项目显示为选定项目,但是如何取消选中导航视图的选中项?
这将取消选中项目:
int size = mNavigationView.getMenu().size();
for (int i = 0; i < size; i++) {
mNavigationView.getMenu().getItem(i).setCheckable(false);
}
我看到了@arsent 的解决方案并试了一下,它确实会做你想做的事,即取消select 所有项目...但是,我在下面遇到了问题场景:
- Select 菜单项 1(使用
NavigationView#setCheckedItem
) - 根据@arsent 的解决方案取消select 所有项目 再次
- 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);
}