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 本身开箱即用,把这些细节做好,底部导航就从「能用」变成「好用」了。

相关推荐
警醒与鞭策17 小时前
Codex桌面版与Claude桌面版使用设置
android·unity·ai·性能优化
传奇开心果20 小时前
【Compose Multiplatform跨端声明式UI实用技术】第19课:多平台部署与发布
android·kotlin
红尘伴蝶舞20 小时前
加密拦截器让抓包失效,我只能从 4KB 的 logcat 碎片里拼回 JSON
android·kotlin·ai编程
booboosui20 小时前
219 个还是 0 个:读不到微信界面时,我只加不删
android
Android打工仔20 小时前
Compose 中何时该用 padding,何时该用 offset
android·android jetpack
二流小码农20 小时前
HarmonyOS开发助手,0代码让元服务从开发到上架
android·ios·harmonyos
limit007520 小时前
三维 WebGIS 工具选型:加载、样式、分析、交付,一套界面能做完什么
android·前端·web3·安卓·webgl
骑着蜗牛撵大象3271 天前
让 Codex 值夜班:把告警排查与巡检接成可回滚的自动化链路
android·java·运维·ai·自动化·codex·智能体
2401_885885041 天前
芬兰语音通知接口怎样对接?语音提醒接入流程
android·前端·python·php·语音识别
程序猿老A1 天前
轻量应用服务器怎么用phpcms搭建网站?
android