Android Studio 使用BottomNavigationView 实现底部 tabs (一)

一、在androidStudio中实现tabs比较简单,新建项目就可以选择tabs模板进行创建,默认实现tabs功能:

直接运行项目就可以看到效果:

可以说非常简单,但是我们在实际开发中默认的效果往往无法满足我们的需求,那么就需要根据自己的需求进行完善优化。

比如我们需要有五个tab,比如需要tab不仅可以点击,还可以滑动切换等等。

二、首先扩充tab至5个,只需要修改res/menu/navigation.xml 这个文件,新增两个配置即可:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">

    <item
        android:id="@+id/navigation_home"
        android:icon="@drawable/ic_home_black_24dp"
        android:title="@string/title_home" />

    <item
        android:id="@+id/navigation_dashboard"
        android:icon="@drawable/ic_dashboard_black_24dp"
        android:title="@string/title_dashboard" />

    <item
        android:id="@+id/navigation_notifications"
        android:icon="@drawable/ic_notifications_black_24dp"
        android:title="@string/title_notifications" />

    <item
        android:id="@+id/navigation_tab4"
        android:icon="@drawable/ic_notifications_black_24dp"
        android:title="@string/title_tab4" />

    <item
        android:id="@+id/navigation_tab5"
        android:icon="@drawable/ic_notifications_black_24dp"
        android:title="@string/title_tab5" />

</menu>

同时需要在Strings.xml里添加tabtitle配置:

<resources>
    <string name="app_name">TabsDem</string>
    <string name="title_home">Home</string>
    <string name="title_dashboard">Dashboard</string>
    <string name="title_notifications">Notifications</string>
    <string name="title_tab4">tab4</string>
    <string name="title_tab5">tab5</string>
</resources>

还需要修改MainActivity里的方法:

private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
            = new BottomNavigationView.OnNavigationItemSelectedListener() {

        @Override
        public boolean onNavigationItemSelected(@NonNull MenuItem item) {
            switch (item.getItemId()) {
                case R.id.navigation_home:
                    mTextMessage.setText(R.string.title_home);
                    return true;
                case R.id.navigation_dashboard:
                    mTextMessage.setText(R.string.title_dashboard);
                    return true;
                case R.id.navigation_notifications:
                    mTextMessage.setText(R.string.title_notifications);
                    return true;
                case R.id.navigation_tab4:
                    mTextMessage.setText(R.string.title_tab4);
                    return true;
                case R.id.navigation_tab5:
                    mTextMessage.setText(R.string.title_tab5);
                    return true;
            }
            return false;
        }
    };

此时运行项目会看到已经添加成功:

此时会发现,不管点击哪个tab,只有当前tab的text会显示,其他tab只显示图标,这显然是有问题的,这是因为BottomNavigationView 默认是三个tab的,如果超过三个,就会出现当前问题。

据说在API28之前是需要使用反射机制解决的,28及之后 加一个配置即可 app:labelVisibilityMode="labeled":

由于我们使用的API28编译,所以运行效果正常,此时我们吧编译环境改为27,再次运行会发现报错:

说的是没有找到 labelVisibilityMode 这个属性,因为现在是API27编译,此时还没有这个属性,那么之后就需要使用反射机制来解决。
这里的问题出在 BottomNavigationMenuView 的 mShiftingMode 上,可以查看源码:

当tab大于3时,会将ShiftingMode设置为true,那么我们现在就需要将所有tab的ShiftingMode这是为false即可:这里新建一个类,这里注意当api大于等于28就不需要以下处理:

public class BottomNavigationViewHelper {
    @SuppressLint("RestrictedApi")
    public static void disableShiftMode(BottomNavigationView view) {
        BottomNavigationMenuView menuView = (BottomNavigationMenuView) view.getChildAt(0);
        try {
            Field shiftingMode = menuView.getClass().getDeclaredField("mShiftingMode");
            shiftingMode.setAccessible(true);
            shiftingMode.setBoolean(menuView, false);
            shiftingMode.setAccessible(false);
            for (int i = 0; i < menuView.getChildCount(); i++) {
                BottomNavigationItemView item = (BottomNavigationItemView) menuView.getChildAt(i);
                item.setShiftingMode(false);   //设置每一个tab为fales
                item.setChecked(item.getItemData().isChecked());
            }
        } catch (NoSuchFieldException e) {
            Log.e("BNVHelper", "Unable to get shift mode field", e);
        } catch (IllegalAccessException e) {
            Log.e("BNVHelper", "Unable to change value of shift mode", e);
        }
    }
}

在MainActivity的onCreate最后一行添加: BottomNavigationViewHelper.disableShiftMode(navigation); 如:

此时运行项目,会发现tab已经都可以正常显示了:

三、那么能不能加到6个呢,尝试之后发现会报错:

Caused by: java.lang.IllegalArgumentException: Maximum number of items supported by BottomNavigationView is 5. Limit can be checked with BottomNavigationView#getMaxItemCount()
        at android.support.design.internal.BottomNavigationMenu.addInternal(BottomNavigationMenu.java:45)
……………………………………

为什么呢?进入 BottomNavigationView 源码看一下,会发现源码里有这么一句:

直接返回最大item数量为5个,已经在代码里固定了,所以以上错误会显示最大数量为5 的错误。


实例代码:https://download.csdn.net/download/ssdate/11040915