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