147

我正在使用android.support.design.widget.BottomNavigationView支持库中的新功能。如何从代码中设置当前选择?我意识到,在旋转屏幕后,选择又变回了第一项。当然,如果有人能告诉我,如何BottomNavigationViewonPause函数中“保存”当前状态以及如何在onResume.

谢谢!

4

23 回答 23

211

从 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 之前设置侦听器(我相信您希望侦听器中的代码在调用此方法时运行)。如果在添加菜单项和设置侦听器之前调用 setSelectedItemId,则不会发生任何事情。

于 2017-03-30T12:09:52.133 回答
73

要以编程方式单击您需要使用的 BottomNavigationBar 项目:

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

这样可以正确排列所有带有标签的项目。

于 2017-01-30T23:40:20.130 回答
50

对于那些仍然使用 SupportLibrary < 25.3.0 的人

我不确定这是否是这个问题的完整答案,但我的问题非常相似 - 我必须处理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的导航视图并找到合适的解决方案。

于 2016-11-21T13:10:06.727 回答
35
bottomNavigationView.setSelectedItemId(R.id.action_item1);

action_item1菜单项 ID在哪里。

于 2018-12-14T11:14:09.893 回答
12

使用它通过菜单 id 设置选定的底部导航菜单项

MenuItem item = mBottomNavView.getMenu().findItem(menu_id);
item.setChecked(true);
于 2020-03-23T05:23:25.617 回答
10

采用

        bottomNavigationView.getMenu().getItem(POSITION).setChecked(true);
于 2020-01-03T18:14:01.357 回答
9
@Override
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);

   bottomNavigationView.setOnNavigationItemSelectedListener(this);
   Menu menu = bottomNavigationView.getMenu();
   this.onNavigationItemSelected(menu.findItem(R.id.action_favorites));
}
于 2016-11-24T19:19:01.563 回答
9

现在可以从 25.3.0 版本开始调用setSelectedItemId()\o/

于 2017-03-28T08:14:08.157 回答
7

添加android:enabled="true"到底部导航菜单项。

然后bottomNavigationView.setOnNavigationItemSelectedListener(mListener)通过做设置并将其设置为选中bottomNavigationView.selectedItemId = R.id.your_menu_id

于 2018-06-23T17:48:08.470 回答
4

这可能会在即将到来的更新中添加。但与此同时,为了实现这一点,您可以使用反射。

创建一个从 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"/>
于 2016-10-28T23:54:01.320 回答
4

我不想修改你的代码。如果是这样,我推荐你试试BottomNavigationViewEx。</p>

你只需要替换调用一个方法setCurrentItem(index);getCurrentItem()。</p>

点击这里查看图片

于 2016-11-13T03:40:05.063 回答
4

只是添加另一种以编程方式执行选择的方式 - 这可能是最初的意图,或者可能是后来添加的。

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

performIdentifierAction需要一个项目Menuid 和一个标志。

有关更多信息,请参阅文档

于 2016-11-20T21:41:53.343 回答
4

似乎在 SupportLibrary 25.1.0 中已修复 :) 编辑:似乎已修复,旋转屏幕时选择的状态已保存。

于 2016-12-20T15:23:49.190 回答
4

在 API 25 以上,您可以使用 setSelectedItemId(menu_item_id) 但在 API 25 下,您必须做不同的事情,用户 Menu 来获取句柄,然后 setChecked 到 Checked 特定项目

于 2018-04-05T13:44:06.910 回答
4

您可以尝试 performClick 方法:

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

编辑

从 API 25.3.0 开始,它引入了一种方法setSelectedItemId(int id),可让您将项目标记为已选中,就好像它已被点击一样。

于 2018-10-11T01:21:03.730 回答
4
navigationView.getMenu().findItem(R.id.navigation_id).setChecked(true);
于 2021-04-01T15:50:03.403 回答
2

我向 Google 提出了一个错误,即没有可靠的方法来选择 BottomNavigationView 上的页面: https ://code.google.com/p/android/issues/detail?id=233697

NavigationView 显然有一个类似的问题,他们通过添加一个新的 setCheckedItem() 方法来解决这个问题。

于 2017-02-08T06:26:21.113 回答
2

我希望这有帮助

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

它更多的是确定与相应的底部导航菜单项同时加载的默认片段。您可以在 OnResume 回调中包含相同的内容

于 2020-02-08T11:45:41.903 回答
0

反思是个坏主意。

前往这个要点。有一个方法可以执行选择但也调用回调:

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

    }
于 2016-11-15T22:50:10.700 回答
0
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);
    }
}

解决方案的唯一“减号”是 using MenuItemImpl,它是库的“内部”(尽管是公共的)。

于 2017-01-04T05:49:59.123 回答
0

如果您需要动态传递片段参数,请执行此操作

这里有很多(大部分是重复的或过时的)答案,但没有一个能处理一个非常常见的需求:动态地将不同的参数传递给加载到 tab 的 Fragment

您不能通过 using 动态地将不同的参数传递给加载的 Fragment setSelectedItemId(R.id.second_tab),这最终会调用 static OnNavigationItemSelectedListener。为了克服这个限制,我最终在MainActivity包含选项卡的我中这样做:

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

ArticleFragment.newInstance()方法照常实现:

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

}
于 2019-08-16T14:53:45.827 回答
0

这种方法对我有用。

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

例子

 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()
    }
于 2020-07-14T10:04:36.380 回答
0

要更改选项卡,此代码有效!

    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
于 2022-02-27T05:47:38.147 回答