在底部导航视图中设置最初选择的项目索引/id

Posted

技术标签:

【中文标题】在底部导航视图中设置最初选择的项目索引/id【英文标题】:Set initially selected item index/id in BottomNavigationView 【发布时间】:2017-03-07 07:33:36 【问题描述】:

我已经实现了BottomNavigationView,但不知道如何设置选择索引或MenuItem id(在我的情况下,应该默认选择中间项)。

恐怕目前还没有这种可能性,因为它太原始了,但无论如何,我们将不胜感激。谢谢!

【问题讨论】:

参考此链接。 androidgifts.com/… 是的,我知道 BottomBar,但我不敢相信 support.design 的人不可能以编程方式选择项目 :) 也许一些 hacky 解决方案...... 看this answer。这是最好的解决方案。 添加了更多“优雅”的答案,你可以去看看。 【参考方案1】:

使用setSelectedItemId设置选中的菜单项ID:

bottomNavigationView.setSelectedItemId(R.id.item_id);

Android 支持库 25.3.0 开始提供此方法。

【讨论】:

【参考方案2】:

对我有用的唯一解决方案是:

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

只需执行点击即可。希望我们能在未来的版本中获得额外的方法/属性。

UPD:

作为user5968678mentioned,从Android Support Library v25.3.0开始添加了一个新方法:

bottomNavigationView.setSelectedItemId(R.id.item_id);

所以改用这个:)

【讨论】:

最好的解决方案【参考方案3】:

我认为这个解决方案比公认的答案更优雅:

bottomNavigationView.getMenu().getItem(menuItemIndex).setChecked(true)

其中 menuItemIndex 是所选元素的索引。

【讨论】:

不起作用。如果您在bottomNavigationBar 上启用了动画,您可以看到所选项目的颜色已更改,但动画仍在菜单的第一项上。目前在 android lib 中不可用。如果你想让它工作: ((BottomNavigationMenuView) bottomNavigationView.getChildAt(0)).getChildAt(menuItemIndex).performClick();甚至更好: ((BottomNavigationMenuView) bottomNavigationView.getChildAt(0)).findViewById(R.id.id_menu_action).performClick(); 你能发布你的代码吗?我正在使用来自谷歌支持库(25.1.0)的最新 BottomNavigationView,当我更改所选索引时,动画可以正常工作。 这只会将菜单设置为活动状态,但不会触发菜单本身,这正是我要寻找的【参考方案4】:

the documentation 对此是这么说的:

菜单项也可用于以编程方式选择当前处于活动状态的目的地。可以使用MenuItem#setChecked(true)

除了 Jan 发布的内容之外,您还可以通过 id 找到该项目:

Menu menu = findViewById(R.id.navigation).getMenu();
menu.findItem(R.id.navigation_home).setChecked(true);

另外,一般来说,我建议您致电.callOnClick() instead of .performClick()

【讨论】:

【参考方案5】:

如果你正在使用监听器,比如 android studio 中的默认实现,试试这个:

BottomNavigationView navigation = (BottomNavigationView) findViewById(R.id.navigation);
Integer indexItem = 4;
navigation.getMenu().getItem(indexItem).setChecked(true);
mOnNavigationItemSelectedListener.onNavigationItemSelected(navigation.getMenu().getItem(indexItem));

【讨论】:

【参考方案6】:

我相信根据这里的答案,在不同的背景下看待这个背景下的问题。 根据评估,需要的是能够专注于特定的BottomNavigationView项目(肯定是在持有不同片段的新类中)。

现在,您可以使用 BottomNavigationView 或按钮或任何可点击的东西来启动新的意图活动:-

Intent intent = new Intent(getActivity(), New_Activity.class);
    intent.putExtra("EXTRA_PAGE, 1);
    startActivityForResult(intent, 30);

那么 - 在我们的 New_Activity 中,我们接收到意图-

意图意图 = getIntent(); int page = intent.getExtras().getInt("EXTRA_PAGE);

然后我们遍历 page 变量以找到当前 BottomNavigationView 所反映的 number/Index,然后 我们设置焦点菜单项(假设您的 BottomNavigationView 具有用于显示的菜单项)

     if(page == 1) 
         currentselect = new Pending();
            bottomNavigationView.getMenu().getItem(0).setChecked(true);

这回答了上面的问题。通过调用上面的帖子数可以很好地处理 Fragment 开关的其余部分:

bottomNavigationView.setOnNavigationItemSelectedListener(navListener);

然后是这样的:

   private BottomNavigationView.OnNavigationItemSelectedListener navListener =
        new BottomNavigationView.OnNavigationItemSelectedListener()
            @Override
            public boolean onNavigationItemSelected(@NonNull MenuItem item) 
                Fragment selectedFrag = null;
                switch (item.getItemId()) 
                    case R.id.pending:
                        selectedFrag = new Pending();
                        break;
                    case R.id.onTransmit:
                        selectedFrag = new inTransmit();
                        break;
                    case R.id.complete:
                        selectedFrag = new Complete();
                        break;
                

                getSupportFragmentManager().beginTransaction().replace(R.id.select_field, selectedFrag).commit();

                return true;
            
        ;

注意: 使用 BottomNavigationViewContentFrameLayout 非常经济,并且与使用 ViewPager 之类的类似,可以将您的代码削减 50% 以上表格布局

【讨论】:

【参考方案7】:

bottomnavigation.BottomNavigationView 中初始选定项的 Kotlin 代码:

bottom_navigation_view.selectedItemId = R.id.navigation_item_messages

【讨论】:

【参考方案8】:

停止使用反射!很糟糕!

好吧,虽然支持库没有让我们选择从BottomNavigationView 中选择项目以在第一次可见时显示,但我们有两种可能性:

首先,使用循环:

private void setupBottomNavigationView() 
    // Get the menu from our navigationBottomView.
    Menu bottomNavigationViewMenu = bottomNavigationView.getMenu();
    // Uncheck the first menu item (the default item which is always checked by the support library is at position 0).
    bottomNavigationMenu.findItem(R.id.action_one).setChecked(false);
    // Check the wished first menu item to be shown to the user.
    bottomNavigationMenu.findItem(R.id.action_two).setChecked(true);

    bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() 
        @Override
        public boolean onNavigationItemSelected(@NonNull MenuItem item) 

    Menu bottomNavigationMenu = bottomNavigationView.getMenu();
            for (int i = 0; i < bottomNavigationMenu.size(); i++) 
                if (item.getItemId() != bottomNavigationMenu.getItem(i).getItemId()) 
                    bottomNavigationMenu.getItem(i).setChecked(false);
                
            

            switch (item.getItemId()) 
                case R.id.action_one :
                    replaceFragment(new OneFragment());
                    break;
                case R.id.action_two :
                    replaceFragment(new TwoFragment());
                    break;
                case R.id.action_three :
                    replaceFragment(new ThreeFragment());
                    break;
            
            return false;
        
    );

其次,没有循环但有一个类变量(因为逻辑是在内部类中完成的):

private void setupBottomNavigationView() 
    // Get the menu from our navigationBottomView.
    Menu bottomNavigationViewMenu = bottomNavigationView.getMenu();
    // Uncheck the first menu item (the default item which is always checked by the support library is at position 0).
    bottomNavigationViewMenu.findItem(R.id.action_one).setChecked(false);
    // Check the wished first menu item to be shown to the user. Also store that menu item on a variable to control when a menu item must be unchecked.
    mActiveBottomNavigationViewMenuItem = bottomNavigationViewMenu.findItem(R.id.action_two).setChecked(true);

    bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() 
        @Override
        public boolean onNavigationItemSelected(@NonNull MenuItem selectedMenuItem) 
            switch (selectedMenuItem.getItemId()) 
                case R.id.action_one :
                    replaceFragment(new OneFragment());
                    break;
                case R.id.action_two :
                    replaceFragment(new TwoFragment());
                    break;
                case R.id.action_three :
                    replaceFragment(new ThreeFragment());
                    break;
            

            if (selectedMenuItem != mActiveBottomNavigationViewMenuItem)
                mActiveBottomNavigationViewMenuItem.setChecked(false);
                mActiveBottomNavigationViewMenuItem = selectedMenuItem;
            

            return false;
        
    );


private MenuItem mActiveBottomNavigationViewMenuItem;

setupBottomNavigationView() 方法何时执行?在Activity的onCreate()方法中,看看:

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    // ...
    setupBottomNavigationView();


简单且无需大量代码。

希望对你有帮助!

【讨论】:

【参考方案9】:

您可以通过添加一个虚拟菜单项来实现此效果 作为您分配给 BottomNavigationView 的菜单中的第一项 并将此项目设置为不可见。然后在 您的重新选择处理程序,调用 setSelectedItem(dummy) 到假人 物品。结果,可见的菜单项将表现为 “虚拟”切换。我花了比应该做的更多的工作 弄清楚这个。你必须这样做才能按顺序 重新选择完成后调用 setSelectItem:

@Override
public void onNavigationItemReselected(@NonNull MenuItem item) 
    anyView.post(new Runnable() 
        @Override
        public void run() 
            navigationView.setSelectedItemId(R.id.action_dummy);
        
    
);

【讨论】:

【参考方案10】:

您可以扩展 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 
            BottomNavigationMenuView menuView = (BottomNavigationMenuView) getField(BottomNavigationView.class, "mMenuView");
            OnNavigationItemSelectedListener listener = (OnNavigationItemSelectedListener) getField(BottomNavigationView.class, "mListener");
            try 
                Method method = menuView.getClass().getDeclaredMethod("activateNewButton", Integer.TYPE);
                method.setAccessible(true);
                // activate item.
                method.invoke(menuView, index);
                if (listener != null) 
                    // trigger item select event.
                    listener.onNavigationItemSelected(getMenu().getItem(index));
                
             catch (SecurityException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) 
                e.printStackTrace();
            
         catch (IllegalAccessException e) 
            e.printStackTrace();
         catch (NoSuchFieldException e) 
            e.printStackTrace();
        
    

    private Object getField(Class clazz, String fieldName) throws NoSuchFieldException, IllegalAccessException 
        Field f = clazz.getDeclaredField(fieldName);
        f.setAccessible(true);
        return f.get(this);
    


【讨论】:

反思是个坏主意!【参考方案11】:

实现BottomNavigationView.OnNavigationItemSelectedListener 并在初始化时设置selectedItemId

this.bottomNavigationView.setOnNavigationItemSelectedListener 
    val targetFragment = when (menuItem.itemId) 
        R.id.action_home -> 
            HomeFragment()
        
        R.id.action_post -> 
            PostFragment()
        
        R.id.action_settings -> 
            SettingsFragment()
        
        else -> null
    
    targetFragment?.let 
        this.activity?.supportFragmentManager?.transaction 
            replace(R.id.containerLayout, it, it.javaClass.simpleName)
        
    
    true


this.bottomNavigationView.selectedItemId = R.id.action_home

【讨论】:

【参考方案12】:

在导航中设置初始页面 - Jetpack Navigation

在导航图中设置属性“startDestination”,值应该是给fragment的id。

<navigation
app:startDestination="@+id/navigation_movies"
...
>

<!--  default page -->
 <fragment
     android:id="@+id/navigation_movies"
     ...`enter code here`
 />
 <fragment
     android:id="@+id/navigation_tv_shows"
     ...
 />
</fragment>

【讨论】:

以上是关于在底部导航视图中设置最初选择的项目索引/id的主要内容,如果未能解决你的问题,请参考以下文章

如何在滚动列表视图上显示/隐藏底部导航视图?

底部导航栏的 Oncreate 视图问题

使用底部导航栏导航回页面时颤动通过底部导航栏选择的索引

底部导航视图中选定选项卡的颜色

每个底部导航视图菜单项的单独导航图 - Android

底部导航视图显示不正确