Set selected item in Android BottomNavigationView

AndroidBottomnavigationview

Android Problem Overview


I am using the new android.support.design.widget.BottomNavigationView from the support library. How can I set the current selection from code? I realized, that the selection is changed back to the first item, after rotating the screen. Of course it would also help, if someone could tell me, how to "save" the current state of the BottomNavigationView in the onPause function and how to restore it in onResume.

Thanks!

Android Solutions


Solution 1 - Android

From API 25.3.0 it was introduced the method setSelectedItemId(int id) which lets you mark an item as selected as if it was tapped.

From docs:

> Set the selected menu item ID. This behaves the same as tapping on an item.

Code example:

BottomNavigationView bottomNavigationView;
bottomNavigationView = (BottomNavigationView) findViewById(R.id.bottomNavigationView);
bottomNavigationView.setOnNavigationItemSelectedListener(myNavigationItemListener);
bottomNavigationView.setSelectedItemId(R.id.my_menu_item_id);

IMPORTANT

You MUST have already added all items to the menu (in case you do this programmatically) and set the Listener before calling setSelectedItemId(I believe you want the code in your listener to run when you call this method). If you call setSelectedItemId before adding the menu items and setting the listener nothing will happen.

Solution 2 - Android

To programmatically click on the BottomNavigationBar item you need use:

View view = bottomNavigationView.findViewById(R.id.menu_action_item);
view.performClick();

This arranges all the items with their labels correctly.

Solution 3 - Android

For those, who still use SupportLibrary < 25.3.0

I'm not sure whether this is a complete answer to this question, but my problem was very similar - I had to process back button press and bring user to previous tab where he was. So, maybe my solution will be useful for somebody:

private void updateNavigationBarState(int actionId){
    Menu menu = bottomNavigationView.getMenu();

    for (int i = 0, size = menu.size(); i < size; i++) {
        MenuItem item = menu.getItem(i);
        item.setChecked(item.getItemId() == actionId);
    }
}

Please, keep in mind that if user press other navigation tab BottomNavigationView won't clear currently selected item, so you need to call this method in your onNavigationItemSelected after processing of navigation action:

@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
    switch (item.getItemId()) {
        case R.id.some_id_1:
            // process action
            break;
        case R.id.some_id_2:
            // process action
            break;
        ...
        default:
            return false;
    }

    updateNavigationBarState(item.getItemId());

    return true;
}

Regarding the saving of instance state I think you could play with same action id of navigation view and find suitable solution.

Solution 4 - Android

bottomNavigationView.setSelectedItemId(R.id.action_item1);

where action_item1 is menu item ID.

Solution 5 - Android

Use this to set selected bottom navigation menu item by menu id

MenuItem item = mBottomNavView.getMenu().findItem(menu_id);
item.setChecked(true);

Solution 6 - Android

use

        bottomNavigationView.getMenu().getItem(POSITION).setChecked(true);

Solution 7 - Android

@Override
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);

   bottomNavigationView.setOnNavigationItemSelectedListener(this);
   Menu menu = bottomNavigationView.getMenu();
   this.onNavigationItemSelected(menu.findItem(R.id.action_favorites));
}

Solution 8 - Android

It is now possible since 25.3.0 version to call setSelectedItemId() \o/

Solution 9 - Android

Add android:enabled="true" to BottomNavigationMenu Items.

And then set bottomNavigationView.setOnNavigationItemSelectedListener(mListener) and set it as selected by doing bottomNavigationView.selectedItemId = R.id.your_menu_id

Solution 10 - Android

This will probably be added in coming updates. But in the meantime, to accomplish this you can use reflection.

Create a custom view extending from BottomNavigationView and access some of its fields.

public class SelectableBottomNavigationView extends BottomNavigationView {

    public SelectableBottomNavigationView(Context context) {
        super(context);
    }

    public SelectableBottomNavigationView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public SelectableBottomNavigationView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public void setSelected(int index) {
        try {
            Field f = BottomNavigationView.class.getDeclaredField("mMenuView");
            f.setAccessible(true);
            BottomNavigationMenuView menuView = (BottomNavigationMenuView) f.get(this);

            try {
                Method method = menuView.getClass().getDeclaredMethod("activateNewButton", Integer.TYPE);
                method.setAccessible(true);
                method.invoke(menuView, index);
            } catch (SecurityException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
                e.printStackTrace();
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }

}

And then use it in your xml layout file.

<com.your.app.SelectableBottomNavigationView
        android:id="@+id/bottom_navigation"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:itemBackground="@color/primary"
        app:itemIconTint="@drawable/nav_item_color_state"
        app:itemTextColor="@drawable/nav_item_color_state"
        app:menu="@menu/bottom_navigation_menu"/>

Solution 11 - Android

I you don't want to modify your code. If so, I recommended you to try BottomNavigationViewEx

You just need replace call a method setCurrentItem(index); and getCurrentItem()

Click here to view the image

Solution 12 - Android

Just adding another way to perform a selection programatically - this is probably what was the intention in the first place or maybe this was added later on.

Menu bottomNavigationMenu = myBottomNavigationMenu.getMenu();
bottomNavigationMenu.performIdentifierAction(selected_menu_item_id, 0);

The performIdentifierAction takes a Menu item id and a flag.

See the documentation for more info.

Solution 13 - Android

Seems to be fixed in SupportLibrary 25.1.0 :) Edit: It seems to be fixed, that the state of the selection is saved, when rotating the screen.

Solution 14 - Android

Above API 25 you can use setSelectedItemId(menu_item_id) but under API 25 you must do differently, user Menu to get handle and then setChecked to Checked specific item

Solution 15 - Android

You can try the performClick method :

View view = bottomNavigationView.findViewById(R.id.YOUR_ACTION);
view.performClick();

Edit

From API 25.3.0 it was introduced the method setSelectedItemId(int id) which lets you mark an item as selected as if it was tapped.

Solution 16 - Android

navigationView.getMenu().findItem(R.id.navigation_id).setChecked(true);

Solution 17 - Android

I made a bug to Google about the fact that there's no reliable way to select the page on a BottomNavigationView: https://code.google.com/p/android/issues/detail?id=233697

NavigationView apparently had a similar issue, which they fixed by adding a new setCheckedItem() method.

Solution 18 - Android

I hope this helps

//Setting default selected menu item and fragment
        bottomNavigationView.setSelectedItemId(R.id.action_home);
        getSupportFragmentManager()
                .beginTransaction()
                .replace(R.id.fragment_container, new HomeFragment()).commit();

It is more of determining the default fragment loaded at the same time with the corresponding bottom navigation menu item. You can include the same in your OnResume callbacks

Solution 19 - Android

Reflection is bad idea.

Head to this gist. There is a method that performs the selection but also invokes the callback:

  @CallSuper
    public void setSelectedItem(int position) {
        if (position >= getMenu().size() || position < 0) return;

        View menuItemView = getMenuItemView(position);
        if (menuItemView == null) return;
        MenuItemImpl itemData = ((MenuView.ItemView) menuItemView).getItemData();


        itemData.setChecked(true);

        boolean previousHapticFeedbackEnabled = menuItemView.isHapticFeedbackEnabled();
        menuItemView.setSoundEffectsEnabled(false);
        menuItemView.setHapticFeedbackEnabled(false); //avoid hearing click sounds, disable haptic and restore settings later of that view
        menuItemView.performClick();
        menuItemView.setHapticFeedbackEnabled(previousHapticFeedbackEnabled);
        menuItemView.setSoundEffectsEnabled(true);


        mLastSelection = position;

    }

Solution 20 - Android

private void setSelectedItem(int actionId) {
    Menu menu = viewBottom.getMenu();
    for (int i = 0, size = menu.size(); i < size; i++) {
        MenuItem menuItem = menu.getItem(i);
        ((MenuItemImpl) menuItem).setExclusiveCheckable(false);
        menuItem.setChecked(menuItem.getItemId() == actionId);
        ((MenuItemImpl) menuItem).setExclusiveCheckable(true);
    }
}

The only 'minus' of the solution is using MenuItemImpl, which is 'internal' to library (though public).

Solution 21 - Android

IF YOU NEED TO DYNAMICALLY PASS FRAGMENT ARGUMENTS DO THIS

There are plenty of (mostly repeated or outdated) answers here but none of them handles a very common need: dynamically passing different arguments to the Fragment loaded into a tab.

You can't dynamically pass different arguments to the loaded Fragment by using setSelectedItemId(R.id.second_tab), which ends up calling the static OnNavigationItemSelectedListener. To overcome this limitation I've ended up doing this in my MainActivity that contains the tabs:

fun loadArticleTab(articleId: String) {
    bottomNavigationView.menu.findItem(R.id.tab_article).isChecked = true // use setChecked() in Java
    supportFragmentManager
        .beginTransaction()
        .replace(R.id.main_fragment_container, ArticleFragment.newInstance(articleId))
        .commit()
}

The ArticleFragment.newInstance() method is implemented as usual:

private const val ARG_ARTICLE_ID = "ARG_ARTICLE_ID"

class ArticleFragment : Fragment() {

    companion object {
        /**
         * @return An [ArticleFragment] that shows the article with the given ID.
         */
        fun newInstance(articleId: String): ArticleFragment {
            val args = Bundle()
            args.putString(ARG_ARTICLE_ID, day)
            val fragment = ArticleFragment()
            fragment.arguments = args
            return fragment
        }
    }

}

Solution 22 - Android

This method work for me.

private fun selectBottomNavigationViewMenuItem(bottomNavigationView : BottomNavigationView,@IdRes menuItemId: Int) {
            bottomNavigationView.setOnNavigationItemSelectedListener(null)
            bottomNavigationView.selectedItemId = menuItemId
            bottomNavigationView.setOnNavigationItemSelectedListener(this)
        }

> Example

 override fun onBackPressed() {
        replaceFragment(HomeFragment())
        selectBottomNavigationViewMenuItem(navView, R.id.navigation_home)
    }



private fun replaceFragment(fragment: Fragment) {
        val transaction: FragmentTransaction = supportFragmentManager.beginTransaction()
        transaction.replace(R.id.frame_container, fragment)
        transaction.commit()
    }

Solution 23 - Android

To change the Tab, this code works!

    activity?.supportFragmentManager?.beginTransaction().also { fragmentTransaction ->
        fragmentTransaction?.replace(R.id.base_frame, YourFragment())?.commit()
    }

    val bottomNavigationView: BottomNavigationView = activity?.findViewById(R.id.bottomNavigationView) as BottomNavigationView
    bottomNavigationView.menu.findItem(R.id.navigation_item).isChecked = true

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMichaelView Question on Stackoverflow
Solution 1 - AndroidRicardoView Answer on Stackoverflow
Solution 2 - AndroiddianakarenmsView Answer on Stackoverflow
Solution 3 - AndroidViacheslavView Answer on Stackoverflow
Solution 4 - AndroidAshwiniView Answer on Stackoverflow
Solution 5 - Androidvhad01View Answer on Stackoverflow
Solution 6 - AndroidbehradView Answer on Stackoverflow
Solution 7 - AndroidAskar SyzdykovView Answer on Stackoverflow
Solution 8 - AndroidBoyView Answer on Stackoverflow
Solution 9 - AndroidRumaan KhalanderView Answer on Stackoverflow
Solution 10 - AndroidcpienoviView Answer on Stackoverflow
Solution 11 - AndroidittianyuView Answer on Stackoverflow
Solution 12 - AndroidDarwindView Answer on Stackoverflow
Solution 13 - AndroidMichaelView Answer on Stackoverflow
Solution 14 - AndroidmhheydarchiView Answer on Stackoverflow
Solution 15 - Androidismail alaouiView Answer on Stackoverflow
Solution 16 - AndroidReza AbiriView Answer on Stackoverflow
Solution 17 - AndroidJohan PaulView Answer on Stackoverflow
Solution 18 - AndroidZephania MwandoView Answer on Stackoverflow
Solution 19 - AndroidNikola DespotoskiView Answer on Stackoverflow
Solution 20 - AndroidAlexeyView Answer on Stackoverflow
Solution 21 - AndroidAlbert Vila CalvoView Answer on Stackoverflow
Solution 22 - Androidcode4roxView Answer on Stackoverflow
Solution 23 - AndroidDiego SalcedoView Answer on Stackoverflow