bbedward
bbedward

Reputation: 6478

Android: NavigationView selector for itemBackground

I have a NavigationView, with many items in it.

I'm trying to change the background of the selected (checked) item. I have a selector that changes the itemTextColor and that works fine.

I have a drawable resource:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
    <solid android:color="@color/selected_item_accent"/>
</shape>

And my selector:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/nav_view_background" android:state_checked="true" />
    <item android:drawable="@drawable/nav_view_background" android:state_pressed="true" />
    <item android:drawable="@android:color/transparent" />
</selector>

And lastly the NavigationView

<android.support.design.widget.NavigationView
    android:id="@+id/navView"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_gravity="start"
    android:background="@color/window_background"
    app:itemTextColor="@drawable/selector_nav_view_text"
    app:itemBackground="@drawable/selector_nav_view_background"
    app:headerLayout="@layout/app_nav_header" />

The pressed state works as expected, but the selected item background does not change.

I'm wondering what I'm doing wrong here. Thanks.

Upvotes: 1

Views: 1025

Answers (1)

AssIstne
AssIstne

Reputation: 466

Search result

Change the color of a checked menu item in a navigation drawer

BUT i dont think it will work, because in the source code, it never set the real item of RecyclerView (not the item of menu) checked. That means when you click the item, only the item of menu checked. So of course the background will not changed.

Workaround

It seems that NavigationView is not designed for what you want. The designer may think that, when user clicks item in NavigationView, it should be closed and the app will navigate user to another page. So setChecked() is not needed;

BUT there is a workaround using reflection. the core code is like

navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
    @Override
    public boolean onNavigationItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.navigation_menu_item_1:
                // find out the position of the menu item in Adapter
                // in my test demo, positionInAdapter = positionInMenu + 2
                int positionInAdapter = NUMBER;
                try {
                    Field presenterField = mNavigationSpan.getClass().getDeclaredField("mPresenter");
                    presenterField.setAccessible(true);
                    // get NavigationMenuPresenter from your NavigationView
                    NavigationMenuPresenter presenter = (NavigationMenuPresenter) presenterField.get(mNavigationSpan);
                    Field menuViewField = presenter.getClass().getDeclaredField("mMenuView");
                    menuViewField.setAccessible(true);
                    // get NavigationMenuView from NavigationMenuPresenter, it is a RecyclerView which contains the real items user seen
                    NavigationMenuView menuView = (NavigationMenuView) menuViewField.get(presenter);
                    // using RecyclerView.findViewHolderForAdapterPosition() to get the ViewHolder, then you can get the itemView
                    menuView.findViewHolderForAdapterPosition(positionInAdapter).itemView.setSelected(true);
                } catch (NoSuchFieldException | IllegalAccessException e) {
                    e.printStackTrace();
                }
                break;
        }
        return false;
    }
});

Note

  1. as the ViewHolder.itemView is a View which doesnt have the setChecked method, so we use selected instead of checked;So you need to changed your background drawable xml, just change android:state_checked to android:state_selected
  2. using reflection is NOT a good idea, i will recommend you to write your own layout to feed your need instead of using NavigationView.

Upvotes: 2

Related Questions