1

I have an app with a NavigationView and two tabs a and b. Two MenuItems in the NavigationView correspond to tab a and b so that, when tab a is selected, NavigationView MenuItem A should be selected, and the same for MenuItem B. Selecting MenuItem A and B should also change tab to a and b correspondingly. Selected here means changing the colors of the icon and text using a selector like this:

colors_navigationview.xml:

<selector xmlns:android="http://schemas.android.com/apk/res/android" >

    <item   android:state_checked="true"
            android:color="@color/red"
            android:drawable="@color/red" />

    <item   android:state_checked="false"
            android:color="@color/gray"
            android:drawable="@color/gray" />

</selector>

NavigationView definition in layout:

<android.support.design.widget.NavigationView
    android:id="@+id/my_navigationview"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_gravity="start"
    app:headerLayout="@layout/my_navigationview_header"
    app:menu="@menu/my_navigationview"
    app:itemIconTint="@drawable/colors_navigationview"
    app:itemTextColor="@drawable/colors_navigationview"
    />

The MenuItems are contained in a SubMenu, defined like this:

my_navigationview.xml

<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/navigation_menu"
        android:title="@string/foo">
        <menu>
            <item
                android:id="@+id/my_navigationview_tab1"
                android:icon="@drawable/fooicon"
                android:title="@string/bar"/>
            <item
                android:id="@+id/my_navigationview_tab2"
                android:icon="@drawable/baricon"
                android:title="@string/barg"/>
        </menu>
    </item>
</menu> 

The problem is that, when selecting tab a or b, be it by clicking the tabs directly or swiping the ViewPager for the tabs, the MenuItems A and Bs colors are not updated. Selecting the MenuItems directly in the NavigationView works, however, and the exact same code is called. Thus I am a bit baffled as to why this does not work.

To summarize:

  1. Selecting a MenuItem in the NavigationView sets the correct color and changes tab. Everything is ok.
  2. Selecting a tab changes the tab, but the selection color is not changed. I think the MenuItem is set to selected, since MenuItem.setSelected(true) is called.

What can I try to fix this issue? I am currently at a loss - this should be an easy thing to do IMO. I have tried the following and more:

  1. Various suggestions from this question.
  2. Invalidating various GUI elements, also the NavigationView and DrawerLayout.

Relevant methods in my Activity

@Override
public void onCreate()
{
    // ...
    // mTabLayout and mViewPager are created properly.
    mTabLayout.setOnTabSelectedListener(new TabLayout.ViewPagerOnTabSelectedListener(mViewPager)
        {
            @Override
            public void onTabSelected(TabLayout.Tab tab)
            {
                super.onTabSelected(tab);
                updateNavigationViewSelection();
            }
        });
}

@Override
public void onResume()
{
    // ...

    // To set correct NavigationView when resuming. Actually works ok at startup.
    updateNavigationViewSelection();
}

public void updateNavigationViewSelection()
{
    int currentItem = mViewPager.getCurrentItem();
    selectNavigationMenuItem(currentItem);
}

public void selectNavigationMenuItem(int tab)
{
    MenuItem menuItem = null;
    NavigationView navigationView = (NavigationView) findViewById(R.id.my_navigationview);
    switch (tab)
    {
        case TAB1:
            menuItem = getNavigationMenuItemTab1();
            break;

        case TAB2:
            menuItem = getNavigationMenuItemTab2();
            break;
    }

    if (menuItem != null)
    {
        unselectAllNavigationMenuItems(); // Calls setChecked(false) on all MenuItems, may be commented out for testing.

        // We arrive here, from onTabSelected(), onResume() and onNavigationItemSelected().
        // onResume() sets the color correctly, as does onNavigationItemSelected(),
        // but *not* when calling from onTabSelected(). All the values seem to be correct, but nothing happens.
        // It seems that checked is set to true, but there is some invalidation missing.
        // Invalidating NavigationView or DrawerLayout does nothing.
        menuItem.setChecked(true);
    }
}

@Override
public boolean onNavigationItemSelected(MenuItem menuItem)
{
    switch (menuItem.getItemId())
    {
        case R.id.my_navigationview_tab1:
            selectNavigationMenuItem(TAB1);
            // Close drawer.
            return true;

        case R.id.my_navigationview_tab2:
            selectNavigationMenuItem(TAB2);
            // Close drawer.
            return true;

        default:
            return false;

    }
}

@Nullable
private MenuItem getNavigationMenuItemTab1()
{
    MenuItem navigationMenu = getNavigationMenu();
    return navigationMenu == null ? null : navigationMenu.getSubMenu().findItem(R.id.my_navigationview_tab1);
}

@Nullable
private MenuItem getNavigationMenuItemTab2()
{
    MenuItem navigationMenu = getNavigationMenu();
    return navigationMenu == null ? null : navigationMenu.getSubMenu().findItem(R.id.my_navigationview_tab2);
}

@Nullable
private MenuItem getNavigationMenu()
{
    NavigationView navigationView = (NavigationView) findViewById(R.id.my_navigationview);
    return navigationView == null ? null : navigationView.getMenu().findItem(R.id.navigation_menu);
}

private void unselectAllNavigationMenuItems()
{
    MenuItem item;
    item = getNavigationMenuItemTab1();
    if (item != null)
        item.setChecked(false);
    item = getNavigationMenuItemTab2();
    if (item != null)
        item.setChecked(false);
}
Community
  • 1
  • 1
Krøllebølle
  • 2,878
  • 6
  • 54
  • 79
  • but both menut items are unselected ? – Chris Sherlock May 10 '16 at 18:06
  • The NavigationView has a method to select an item, http://developer.android.com/intl/in/reference/android/support/design/widget/NavigationView.html#setCheckedItem(int) did you tried using it instead of your current code? – user May 10 '16 at 18:07
  • @Chris: At startup, the first MenuItem becomes selected from the onResume() call. Thereafter a single item is always selected, but it is only changed when calling from `selectNavigationMenuItem()`. @Luksprog Yes, I tried using `setCheckedItem()`, but I'll do a double check of that just to make sure. – Krøllebølle May 10 '16 at 18:10
  • I could reproduce this bug and tried it with several methods that did not work too. – Chris Sherlock May 10 '16 at 18:17
  • Ok, good to know that it's just not me having this issue. Just for reference: using `setCheckedItem()` does not change anything for me neither. It makes no difference calling `updateNavigationViewSelection()` from `ViewPager.OnPageChangeListener()`, just for reference. – Krøllebølle May 10 '16 at 18:23

1 Answers1

2

Seems like i found a little workaround.

Several methods in like :

navigationView.getMenu().getItem(indx).setChecked(true);
navigationView.getMenu().findItem(someId).setChecked(true);
navigationView.setCheckedItem(someId);
navigationView.getMenu().performIdentifierAction(someId, 2);

did not work. But if you trigger the event by calling the navigation listener

onNavigationItemSelected(MenuItem)

method it works.

e.g. in your app:

onNavigationItemSelected(getNavigationMenuItemTab1());
Chris Sherlock
  • 931
  • 5
  • 19
  • Which version of the support libraries did you use? I did an upgrade from 23.1.0 to 23.3.0 and now it works as a charm, both with and without using `onNavigationItemSelected()`. Maybe that call fixes an issue somewhere in the previous support libraries? – Krøllebølle May 10 '16 at 18:45
  • I have the most recent support libraries, but these methods did not work for me – Chris Sherlock May 10 '16 at 19:03
  • That is strange. Oh well, I guess we have a workable solution in any case. – Krøllebølle May 10 '16 at 19:05