How to set shared checkable behavior across all groups in NavigationView?
Solution 1
Here's the solution.
Step 1: Remove
android:checkableBehavior="single"
from both groups.
Step 2: Add the following logic to the listener:
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;
}
});
Note: instead of calling menuItem.setCheckable(true)
you can set android:checkable="true"
for each item in XML.
@Moinkhan's solution should work as well (thanks, upvoted), but I didn't want to loop through menu's items each time a new position is selected.
Solution 2
Actually, you don't need separate parallel groups for separators. You can have everything in one group and place submenus (have titles) or subgroups (no title) in it. There will be separators for those submenus and subgroups. This way the checkable behavior works without a workaround. (Fyi: This is on Design Support Lib 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>
In code, I simply do the following and single checking works as expected:
@Override
public boolean onNavigationItemSelected(MenuItem item) {
mNavigationView.setCheckedItem(item.getItemId());
...
}
Solution 3
No need to remove checkableBehavior="single"
, just use
navigationView.setCheckedItem(item.getItemId());
instead of item.setChecked(true)
.
Solution 4
Ok I found the solution ..
just add this snippet code to onNavigationItemSelected
method
@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;
}
that's it .. And yes setChecked(false) not working. Just because from list of menu there should be a one single item must be cheked. So you can only uncheck it when you select another item .. And if you click on selected item, the navigationview will never unchecked it. Just because the scenario i have explaind.
Solution 5
There appears to be an invalidation bug in the NavigationView
implementation, but you don't need to use setCheckable()
, you just need to invalidate the NavigationView
after calling setChecked(false)
, like so:
previousItem.setChecked(false);
navigationView.invalidate();
However the menu group must not have checkableBehavior="single"
, because in exclusive mode calling setChecked(boolean)
on a MenuItem
in the group will set that item as checked whether you pass true or false. So in order for setChecked(false)
to work, you must remove checkableBehavior="single"
from your menu definitions.
I created an issue about this here: https://code.google.com/p/android/issues/detail?id=178709
EyesClear
Updated on July 14, 2022Comments
-
EyesClear almost 2 years
I've created two groups with unique ids (I need a divider) and they both have
checkableBehavior
set to single. This allows multiple items from different groups to be checked at once, and that's exactly what I'm trying to avoid. I'd like to have one item checked at maximum, across all groups.Since I haven't found any way to do this in XML, I tried to implement a simple logic in
onNavigationItemSelected
to uncheck the previous menu item:if (previousItem != null) previousItem.setChecked(false); currentItem.setChecked(true);
but
setChecked(false)
method has never worked for me - the item stays checked.Here's my sample code:
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; } });
I need a hint! Thanks.