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!
From API 25.3.0 it was introduced the method setSelectedItemId(int id)
which let's 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 and set the Listener before calling setSelectedItemId so that the BottomNavigationView can run the corresponding code's behaviour. If you call setSelectedItemId before adding the menu items and setting the listener nothing will happen.
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.
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.
bottomNavigationView.setSelectedItemId(R.id.action_item1);
where action_item1
is menu item ID.
It is now possible since 25.3.0 version to call setSelectedItemId()
\o/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
bottomNavigationView.setOnNavigationItemSelectedListener(this);
Menu menu = bottomNavigationView.getMenu();
this.onNavigationItemSelected(menu.findItem(R.id.action_favorites));
}
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
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"/>
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
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()
。

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.
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.
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.
You can try the performClick method :
View view = bottomNavigationView.findViewById(R.id.YOUR_ACTION);
view.performClick();
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).
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;
}
来源:https://stackoverflow.com/questions/40202294/set-selected-item-in-android-bottomnavigationview