当前位置: 首页 > 工具软件 > Bottom > 使用案例 >

BottomNavigationView 的使用及遇到的坑

庾勇军
2023-12-01

BottomNavigationView 使用

  • 布局中设置
<android.support.design.widget.BottomNavigationView
    android:id="@+id/bottom_navigation"
    style="@style/Widget.Design.BottomNavigationView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:layout_gravity="bottom"
    android:background="@color/viewBackground"
    app:elevation="@dimen/dp_16"
    app:itemIconTint="@drawable/nav_item_color_state"
    app:itemTextColor="@drawable/nav_item_color_state"
    app:menu="@menu/bottom_navigation_main" />
复制代码
  • BottomNavigationView 是通过 menu 来设置 item
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:id="@+id/action_home"
        android:enabled="true"
        android:icon="@drawable/ic_home_black_24dp"
        android:title="@string/home"
        app:showAsAction="ifRoom" />
    <item
        android:id="@+id/action_knowledge_system"
        android:enabled="true"
        android:icon="@drawable/ic_apps_black_24dp"
        android:title="@string/knowledge_system"
        app:showAsAction="ifRoom" />
    <item
        android:id="@+id/action_wechat"
        android:enabled="true"
        android:icon="@drawable/ic_wechat_black_24dp"
        android:title="@string/wechat"
        app:showAsAction="ifRoom" />
    <item
        android:id="@+id/action_navigation"
        android:enabled="true"
        android:icon="@drawable/ic_navigation_black_24dp"
        android:title="@string/navigation"
        app:showAsAction="ifRoom" />
    <item
        android:id="@+id/action_project"
        android:enabled="true"
        android:icon="@drawable/ic_project_black_24dp"
        android:title="@string/project"
        app:showAsAction="ifRoom" />
</menu>
复制代码
  • Activity 中使用
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_bottom_navigation);
    BottomNavigationView navigation = (BottomNavigationView)findViewById(R.id.bottom_navigation);
    navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
}

private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
        = new BottomNavigationView.OnNavigationItemSelectedListener() {
    @Override
    public boolean onNavigationItemSelected(@NonNull MenuItem item) {
        switch (item.getItemId()) {
            case R.id.action_home:
                return true;
            case R.id.action_knowledge_system:
                return true;
            case R.id.action_wechat:
                return true;
            case R.id.action_navigation:
                return true;
            case R.id.action_project:
                return true;
        }
        return false;
    }
};
复制代码

使用时遇到的坑

坑一:使用时 item 个数大于 3 个时会有位移动画,那么如何设置底部图标和字体都显示并去掉点击动画?
  • 使用下面的类通过反射可以修改
public class BottomNavigationViewHelper {
    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);
                //noinspection RestrictedApi
                item.setShiftingMode(false);
                // set once again checked value, so view will be updated
                //noinspection RestrictedApi
                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);
        }
    }
}
复制代码
BottomNavigationViewHelper.disableShiftMode(navigation);
复制代码

另:在support版本 28 以下(不包含)使用上面的方法完美解决,那么在support版本 28 以上怎么解决呢?

support 28 版本官方重构了 BottomNavigationView ,通过查阅 BottomNavigationViewBottomNavigationMenuView 中的代码可以知道通过设置 labelVisibilityMode 的显示模式来设置底部图标和字体都显示并去掉点击动画。

所以目前 support 版本 28 可以使用下面的方法可以完美解决:

java代码中

bottom_navigation.setLabelVisibilityMode(1);
复制代码

或者 xml 布局文件中

app:labelVisibilityMode="labeled"
复制代码
坑二:如何实现中间的 icon 的样式和其他的不一样?
  • app:menu="@menu/bottom_navigation_main" 指向的 bottom_navigation_main 修改为
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:id="@+id/action_home"
        android:enabled="true"
        android:icon="@drawable/ic_home_black_24dp"
        android:title="@string/home"
        app:showAsAction="ifRoom" />
    <item
        android:id="@+id/action_knowledge_system"
        android:enabled="true"
        android:icon="@drawable/ic_apps_black_24dp"
        android:title="@string/knowledge_system"
        app:showAsAction="ifRoom" />
    <item
        android:id="@+id/action_wechat"
        android:enabled="true"
        android:icon="@null"
        android:title=""
        app:showAsAction="ifRoom" />
    <item
        android:id="@+id/action_navigation"
        android:enabled="true"
        android:icon="@drawable/ic_navigation_black_24dp"
        android:title="@string/navigation"
        app:showAsAction="ifRoom" />
    <item
        android:id="@+id/action_project"
        android:enabled="true"
        android:icon="@drawable/ic_project_black_24dp"
        android:title="@string/project"
        app:showAsAction="ifRoom" />
</menu>
复制代码

也就是中间第三个 item 不设置图标和文字。

  • 然后在修改布局文件(用一个 LinearLayout 中间设个一个 ImageView 覆盖在 BottomNavigationView 上即可)
<FrameLayout
    android:layout_width="match_parent"
    android:layout_height="?attr/actionBarSize"
    android:clipToPadding="true">

    <android.support.design.widget.BottomNavigationView
        android:id="@+id/bottom_navigation"
        style="@style/Widget.Design.BottomNavigationView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_gravity="bottom"
        android:background="@color/viewBackground"
        app:elevation="@dimen/dp_16"
        app:itemIconTint="@drawable/nav_item_color_state"
        app:itemTextColor="@drawable/nav_item_color_state"
        app:menu="@menu/bottom_navigation_main" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:elevation="16dp">

        <View
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="2" />

        <ImageView
            android:id="@+id/navigation_center_image"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_gravity="center"
            android:layout_weight="1"
            android:padding="5dp"
            android:src="@mipmap/ic_launcher" />

        <View
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="2" />

    </LinearLayout>
</FrameLayout>
复制代码
坑三:选中 item 时,item 的文本会有一个动画,icon 也会上移一点,那么如何取消动画呢?
  • 下面的参数是 item 选中和没有选中的文本大小,把它们设置成一样的就没有动画了。
design_bottom_navigation_active_text_size
design_bottom_navigation_text_size
复制代码
  • 下面的参数是 iconmargin_bottom 值,可以调整它让 icon 垂直居中。
design_bottom_navigation_margin
复制代码
  • 把下面的根据需要复制到项目的 dimen.xml 文件中即可。
<!--BottomNavigationView 的选中没有选中的字体大小-->
<dimen name="design_bottom_navigation_active_text_size">10sp</dimen>
<dimen name="design_bottom_navigation_text_size">10sp</dimen>

<!--BottomNavigationView 只放图标时的设置-->
<dimen name="design_bottom_navigation_active_text_size">0sp</dimen>
<dimen name="design_bottom_navigation_text_size">0sp</dimen>
<dimen name="design_bottom_navigation_margin">16dp</dimen>
复制代码
 类似资料: