Установить выбранный элемент в Android BottomNavigationView

Я использую новый android.support.design.widget.BottomNavigationView из библиотеки поддержки. Как установить текущий выбор из кода? Я понял, что выбор меняется обратно на первый пункт, после поворота экрана. Конечно, это также помогло бы, если бы кто-то мог сказать мне, как "сохранить" текущее состояние BottomNavigationView на onPause функция и как ее восстановить в onResume.

спасибо!

14 ответов


из API 25.3.0 был введен метод setSelectedItemId(int id) который позволяет вам пометить элемент как выбранный, как если бы он был нажат.

из документов:

установите ID выбранного пункта меню. Этот ведет себя так же, как нажатие на элемент.

пример кода:

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

важно

вы должны уже добавили все элементы в меню и установите прослушиватель перед вызовом setSelectedItemId так что BottomNavigationView может запускать поведение соответствующего кода. Если вы вызываете setSelectedItemId перед добавлением пунктов меню и установкой прослушивателя, ничего не произойдет.


чтобы программно щелкнуть элемент BottomNavigationBar, вам нужно использовать:

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

это упорядочивает все элементы с их метками правильно.


для тех, кто все еще использует SupportLibrary

Я не уверен, что это полный ответ на этот вопрос, но моя проблема была очень похожа - мне пришлось обработать back нажать кнопку и вернуть пользователя на предыдущую вкладку, где он был. Итак, возможно, мое решение кому-то пригодится:

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);
    }
}

пожалуйста, имейте в виду, что если пользователь нажмите вкладку навигации BottomNavigationView не очистит выбранный элемент, поэтому вам нужно вызвать этот метод в ваш onNavigationItemSelected после обработки навигационного действия:

@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;
}

что касается сохранения состояния экземпляра, я думаю, вы могли бы играть с тем же action id навигации посмотреть и найти подходящее решение.


теперь можно с версии 25.3.0 вызывать setSelectedItemId() \o/


это, вероятно, будет добавлено в ближайшие обновления. Но в то же время, для этого вы можете использовать отражение.

создайте пользовательское представление, расширяющееся из BottomNavigationView, и получите доступ к некоторым его полям.

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();
        }
    }

}

а затем используйте его в файле макета xml.

<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"/>

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

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

Я вы не хотите изменять свой код. Если это так, я рекомендовал вам попробовать BottomNavigationViewEx

вам просто нужно заменить вызов метода setCurrentItem(index); и getCurrentItem()

Click here to view the image


кажется, исправлено в SupportLibrary 25.1.0 :) Edit: кажется, исправлено, что состояние выбора сохраняется при вращении экрана.


выше API 25 вы можете использовать setSelectedItemId(menu_item_id) но под API 25 вы должны сделать по-другому, меню пользователя, чтобы получить дескриптор, а затем setChecked для проверки конкретного элемента


просто добавление другого способа выполнения выбора программно-это, вероятно, то, что было намерение в первую очередь, или, может быть, это было добавлено позже.

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

на performIdentifierAction принимает Menu идентификатор элемента и флаг.

посмотреть документация для получения дополнительной информации.


добавить android:enabled="true" к пунктам BottomNavigationMenu.

и затем установить bottomNavigationView.setOnNavigationItemSelectedListener(mListener) и установить его как выбрать bottomNavigationView.selectedItemId = R.id.your_menu_id


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);
    }
}

единственным "минусом" решения является использование MenuItemImpl, который является "внутренним" для библиотеки (хотя и общедоступным).


Я сделал ошибку в Google о том, что нет надежного способа выбрать страницу на BottomNavigationView:https://code.google.com/p/android/issues/detail?id=233697

NavigationView, по-видимому, имел аналогичную проблему, которую они исправили, добавив новый метод setCheckedItem ().


отражение-плохая идея.

этот суть. Существует метод, который выполняет выбор, но также вызывает обратный вызов:

  @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;

    }