Android BottomNavigationView 入门介绍

文章目录

一、什么是 BNV

BottomNavigationView(简称 BNV) 是 Material Components 库提供的一个底部导航控件,固定在页面底部,用于在 3~5 个顶层页面之间快速切换,常见于「首页 / 视频 / 我的」这类 App 结构。

它自带图标 + 文字、选中态变色、点击涟漪反馈,开箱即用,是 Android 官方推荐的底部导航方案。

二、为什么用它

  • 符合 Material 规范:官方组件,样式统一,不用自己手写底部栏。
  • 省事:菜单、选中态、点击反馈都由组件内部处理,只需提供菜单资源。
  • 适合顶层导航:底部是拇指最容易触达的区域,适合放最常用的几个一级入口。

对比一下:TabLayout 一般放在顶部,适合配合 ViewPager2 做内容分页;BNV 放在底部,适合做 App 的全局一级导航。两者用途不同,有时也会一起使用。

三、引入依赖

Material 组件库(新建项目一般已默认带上):

groovy 复制代码
implementation 'com.google.android.material:material:1.12.0'

四、定义菜单

BNV 的每个 Tab 对应一个菜单项,先建 res/menu/bottom_main_menu.xml

xml 复制代码
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/first_page"  android:title="首页" android:icon="@drawable/ic_home" />
    <item android:id="@+id/screen_page" android:title="视频" android:icon="@drawable/ic_screen" />
    <item android:id="@+id/song_page"   android:title="刷歌" android:icon="@drawable/ic_song" />
    <item android:id="@+id/star_page"   android:title="星光" android:icon="@drawable/ic_star" />
    <item android:id="@+id/my_page"     android:title="我的" android:icon="@drawable/ic_user" />
</menu>

菜单项建议控制在 3~5 个:少于 3 个没必要用底部栏,多于 5 个 Material 会退化成「更多」模式,体验变差。

五、布局中声明

xml 复制代码
<com.google.android.material.bottomnavigation.BottomNavigationView
    android:id="@+id/bottom_navigation_view"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="#FFFFFF"
    app:itemIconSize="20dp"
    app:itemIconTint="@color/item_color"
    app:itemTextColor="@color/item_color"
    app:itemRippleColor="@android:color/transparent"
    app:itemActiveIndicatorStyle="@null"
    app:labelVisibilityMode="labeled"
    app:menu="@menu/bottom_main_menu"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent" />

六、常用属性

属性 作用
app:menu 绑定菜单资源,决定有几个 Tab
app:itemIconSize 统一图标尺寸,避免菜单里图标大小不一
app:itemIconTint 图标着色,传 ColorStateList 实现选中变色
app:itemTextColor 文字着色,同样用 ColorStateList
app:itemActiveIndicatorStyle Material3 的选中胶囊背景,传 @null 可去掉
app:itemRippleColor 点击涟漪颜色,传透明可禁用
app:labelVisibilityMode labeled / unlabeled / selected / auto

选中 / 未选中变色,res/color/item_color.xml

xml 复制代码
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:color="#000000" android:state_selected="true"/>
    <item android:color="#AAAAAA" android:state_selected="false"/>
</selector>

七、点击事件

java 复制代码
bnv.setOnItemSelectedListener(item -> {
    int id = item.getItemId();
    if (id == R.id.first_page) {
        switchTo(R.id.first_page);
        return true;   // 返回 true 表示已消费该事件,Tab 会保持选中
    }
    return false;
});

八、配合 Fragment 切换页面

点击 Tab 后一般用 FragmentManager 切换页面。推荐缓存实例,避免每次点击都重新创建 Fragment:

java 复制代码
private final HashMap<Integer, Fragment> pages = new HashMap<>();
private Fragment currentFragment;

private void switchTo(int tabId) {
    Fragment target = pages.get(tabId);
    if (target == null) {
        if (tabId == R.id.first_page) {
            target = new HomeFragment();
        } else {
            return;   // 还没做的页面先忽略
        }
        pages.put(tabId, target);
    }
    if (target == currentFragment) return;

    getSupportFragmentManager().beginTransaction()
            .replace(R.id.fragment_container, target)
            .commit();
    currentFragment = target;
}

HashMap 缓存后,切回某个 Tab 时页面里的滚动位置、列表状态都能保留,不会每次被重置。

九、和 ViewPager2 联动

如果每个 Tab 的内容需要横向滑动切换,可以让 BNV 和 ViewPager2 双向联动:

java 复制代码
// ViewPager2 滑动时同步选中 BNV 的 Tab
viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
    @Override
    public void onPageSelected(int position) {
        bnv.getMenu().getItem(position).setChecked(true);
    }
});

// 点击 BNV 时让 ViewPager2 滚过去
bnv.setOnItemSelectedListener(item -> {
    int index = /* 菜单项对应的下标 */;
    viewPager.setCurrentItem(index, false);
    return true;
});

这种方式适合页面较少、且切换有明显左右滑动语义的场景。

十、常见问题

  1. Material3 多了一个灰色胶囊背景app:itemActiveIndicatorStyle="@null" 去掉。

  2. 各 Tab 图标大小不一致 菜单里的矢量图 viewport 可能不同,用 app:itemIconSize 统一强制尺寸。

  3. 点击后 Tab 又跳回原来那个 setOnItemSelectedListener 里记得对已处理的项 return true

十一、小结

  • 菜单控制在 3~5 项,保持顶层结构清晰;
  • 用 ColorStateList 统一选中 / 未选中配色;
  • 切换页面建议缓存 Fragment 实例,避免状态丢失;
  • 需要横向滑动时再考虑和 ViewPager2 联动;
  • 注意沉浸式布局下给底部留出系统导航栏高度。

BNV 本身开箱即用,把这些细节做好,底部导航就从「能用」变成「好用」了。

相关推荐
Godikov2 小时前
硬件异步事件下的业务一致性:智能柜领取/归还流程的竞态设计
android
Godikov2 小时前
不用 Netty:Android 手写 TCP 客户端实战——自定义协议帧、粘包处理与可靠重连
android
事圆则缓3 小时前
Java 面向对象如何落到 Android View 体系
android
iPad协议个微协议4 小时前
# 微信自动营销系统如何基于 WechatApi 做事件驱动设计
android·微信·企业微信·个人开发·wechatapi·微信个人号开发
AirDroid_cn4 小时前
隐私沙盒:第三方应用读取剪切板内容如何拦截?
android·gitee
2501_915918416 小时前
怎么把 Python 写的 Flet 应用打包成 iOS App 并上架 App Store?
android·ios·小程序·https·uni-app·iphone·webview
邪修king7 小时前
Re:Linux系统篇(二十六):文件系统(二):Ext 文件系统底层详解:从 inode、块组到软硬链接,结合 Windows 讲透文件管理本质
android·java·linux
又见情义8 小时前
RK3568 Android 13 版本号管理实战:基于 ROCKCHIP_BUILD_NUMBER 的定制化方案
android
终端安全笔记8 小时前
iOS 27 强制 TLS 1.2:租赁设备的注册链路会在哪一环断
android·网络·安全·ios·智能手机