NavigationView
Menu:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<group android:checkableBehavior="all">
<item
android:id="@ id/itemFoo1"
android:checkable="true"
android:title="Foo1" />
<item
android:id="@ id/itemFoo2"
android:checkable="true"
android:title="Foo2" />
</group>
</menu>
The designer in Android Studio shows checkboxes:
However, the app does not display checkboxes:
Could anyone offer a clue about this?
The layout using the menu:
<com.google.android.material.navigation.NavigationView
android:id="@ id/navigationView"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="end"
app:menu="@menu/activity_foo_view"/>
CodePudding user response:
The default behavior for the NavigationView
is to select an item at a time; this typically picks a fragment in a drawer layout for instance.
And as Mike M pointed out in comments; making an item checkable doesn't mean that it's a CheckBox
.
So, you have to add a CheckBox
to the menu item, and there are two options to do that:
Option 1: Using a
CheckBox
asapp:actionViewClass
Option 2: Using a custom layout with
app:actionLayout
: Check this answer for that
Using a CheckBox
as app:actionViewClass
:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<group android:checkableBehavior="all">
<item
android:id="@ id/itemFoo1"
android:checkable="true"
app:actionViewClass="android.widget.CheckBox"
android:title="Foo1" />
<item
android:id="@ id/itemFoo2"
android:checkable="true"
app:actionViewClass="android.widget.CheckBox"
android:title="Foo2" />
</group>
</menu>
Hitting the checkBox will toggle its state, but hitting the item text will not; this can be fixed programmatically by getting the menuItem ActionView
and toggle the CheckBox
using setChecked()
:
private final NavigationView.OnNavigationItemSelectedListener navViewlistener = new NavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.itemFoo1 || id == R.id.itemFoo2) {
CheckBox actionView = (CheckBox) item.getActionView();
actionView.setChecked(!actionView.isChecked()); // Toggle the CheckBox
}
return true;
}
};
navView.setNavigationItemSelectedListener(navViewlistener);
UPDATE
I used app:actionViewClass="
android.widget.CheckBox
" for a while. The main issue is the the checkbox is independent of the item. Clicking it does not triggerNavigationItemSelectedListener
. That is the main reason I am seeking a new way.
This is right; we could fix this programmatically by triggering a MenuItem
click event whenever the holding CheckBox
is checked/unchecked.
But the main issue of that, it can cause infinite loop; as we check/uncheck the CheckBox
within onNavigationItemSelected
; and that will trigger another MenuItem
click and so on.
So, here a mIsCheckBoxClick
boolean and also stopping CheckBox
listeners before calling setChecked()
, and reattaching them after that; all that to avoid the loop:
private boolean mIsCheckBoxClick;
@Override
protected void onCreate(Bundle savedInstanceState) {
// ....... add your code
// Enable CheckBox listeners at the NavView menu items by default
addFooListeners(navView, true);
}
private void addFooListeners(final NavigationView navView, boolean enabled) {
adjustNavViewItemListener(navView.getMenu().findItem(R.id.itemFoo1), navView, enabled);
adjustNavViewItemListener(navView.getMenu().findItem(R.id.itemFoo2), navView, enabled);
}
private void adjustNavViewItemListener(final MenuItem item, final NavigationView navView, boolean enabled) {
final CheckBox fooChBox = (CheckBox) item.getActionView();
CompoundButton.OnCheckedChangeListener listener = new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
mIsCheckBoxClick = true;
navView.getMenu().performIdentifierAction(item.getItemId(), 0); // perform a click on MenuItem to trigger OnNavigationItemSelectedListener
}
};
fooChBox.setOnCheckedChangeListener(enabled ? listener : null);
}
private final NavigationView.OnNavigationItemSelectedListener navViewlistener = new NavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.itemFoo1 || id == R.id.itemFoo2) {
// Loop prevention check
if (!mIsCheckBoxClick) {
CheckBox actionView = (CheckBox) item.getActionView();
// Stop the CheckBox listeners
addFooListeners(navView, false);
actionView.setChecked(!actionView.isChecked());
// Reattach the CheckBox listeners
addFooListeners(navView, true);
}
mIsCheckBoxClick = false;
}
return true;
}
};