Android自定义底部导航栏:如何创建及调整指定底部导航栏?
嘿,我来一步步带你搞定Android自定义底部导航栏,不管你是想改官方组件的样式,还是做完全自定义的酷炫效果,都给你安排明白~
官方组件自带了基础的导航逻辑,改改样式就能满足大部分需求,先从这个开始:
- 引入Material组件依赖
在Module级的build.gradle里添加最新版本的Material库:
implementation "com.google.android.material:material:1.9.0"
- 编写布局文件
在你的主Activity布局(比如activity_main.xml)里添加BottomNavigationView:
<com.google.android.material.bottomnavigation.BottomNavigationView android:id="@+id/bottom_nav" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" app:menu="@menu/bottom_nav_menu" app:itemIconSize="24dp" app:itemTextSize="12dp" app:itemIconTint="@color/bottom_nav_color_selector" app:itemTextColor="@color/bottom_nav_color_selector" app:background="@drawable/bottom_nav_background" />
- 定义导航菜单
创建res/menu/bottom_nav_menu.xml,添加每个导航项的图标和文字:
<menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/nav_home" android:icon="@drawable/ic_home" android:title="@string/home" /> <item android:id="@+id/nav_search" android:icon="@drawable/ic_search" android:title="@string/search" /> <item android:id="@+id/nav_profile" android:icon="@drawable/ic_profile" android:title="@string/profile" /> </menu>
- 自定义颜色与背景
- 颜色选择器
res/color/bottom_nav_color_selector.xml,控制选中/未选中状态的颜色:
<selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:color="@color/primary_color" android:state_selected="true" /> <item android:color="@color/grey_500" android:state_selected="false" /> </selector>
- 圆角背景
res/drawable/bottom_nav_background.xml,给导航栏加顶部圆角:
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <solid android:color="@color/white" /> <corners android:topLeftRadius="16dp" android:topRightRadius="16dp" /> <padding android:bottom="8dp" /> </shape>
- 处理选中事件
在Activity里设置导航项的点击逻辑(Kotlin示例):
val bottomNav = findViewById<BottomNavigationView>(R.id.bottom_nav) bottomNav.setOnItemSelectedListener { item -> when (item.itemId) { R.id.nav_home -> { // 切换到首页Fragment/页面 true } R.id.nav_search -> { // 切换到搜索页 true } R.id.nav_profile -> { // 切换到个人页 true } else -> false } }
方案二:完全自定义底部导航栏(自由度拉满)
如果官方组件满足不了你的特殊需求(比如要加自定义动画、特殊布局),那就自己搭一个:
- 编写自定义布局
用LinearLayout或ConstraintLayout做底部容器,每个导航项是ImageView+TextView的组合:
<androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent"> <!-- 页面内容容器 --> <FrameLayout android:id="@+id/content_container" android:layout_width="match_parent" android:layout_height="0dp" app:layout_constraintBottom_toTopOf="@id/custom_bottom_nav" app:layout_constraintTop_toTopOf="parent" /> <!-- 自定义底部导航栏 --> <LinearLayout android:id="@+id/custom_bottom_nav" android:layout_width="match_parent" android:layout_height="60dp" android:background="@drawable/bottom_nav_background" android:orientation="horizontal" android:gravity="center" app:layout_constraintBottom_toBottomOf="parent"> <!-- 首页导航项 --> <LinearLayout android:id="@+id/nav_home_item" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:orientation="vertical" android:gravity="center" android:clickable="true" android:focusable="true"> <ImageView android:id="@+id/home_icon" android:layout_width="24dp" android:layout_height="24dp" android:src="@drawable/home_icon_selector" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/home" android:textSize="12dp" android:textColor="@color/bottom_nav_color_selector" /> </LinearLayout> <!-- 搜索、个人项复制上述结构,修改id和内容即可 --> <!-- ... --> </LinearLayout> </androidx.constraintlayout.widget.ConstraintLayout>
- 图标状态切换
创建res/drawable/home_icon_selector.xml,控制选中/未选中的图标:
<selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@drawable/ic_home_selected" android:state_selected="true" /> <item android:drawable="@drawable/ic_home_unselected" android:state_selected="false" /> </selector>
- 处理点击与状态切换
在Activity里统一管理导航项的选中状态(Kotlin示例):
val homeItem = findViewById<LinearLayout>(R.id.nav_home_item) val searchItem = findViewById<LinearLayout>(R.id.nav_search_item) val profileItem = findViewById<LinearLayout>(R.id.nav_profile_item) // 默认选中首页 homeItem.isSelected = true // 绑定点击事件 homeItem.setOnClickListener { updateNavSelection(homeItem) // 切换到首页 } searchItem.setOnClickListener { updateNavSelection(searchItem) // 切换到搜索页 } profileItem.setOnClickListener { updateNavSelection(profileItem) // 切换到个人页 } // 统一更新选中状态的方法 private fun updateNavSelection(selectedItem: LinearLayout) { listOf(homeItem, searchItem, profileItem).forEach { it.isSelected = false } selectedItem.isSelected = true }
进阶玩法:加动画与动态调整
想让导航栏更生动?试试这些技巧:
- 选中动画
给选中的导航项加图标放大、文字上浮效果:
private fun updateNavSelection(selectedItem: LinearLayout) { listOf(homeItem, searchItem, profileItem).forEach { item -> val icon = item.findViewById<ImageView>(R.id.home_icon) // 对应每个item的图标id val text = item.findViewById<TextView>(R.id.home_text) if (item == selectedItem) { // 选中动画 icon.animate().scaleX(1.2f).scaleY(1.2f).setDuration(200).start() text.animate().translationY(-4f).setDuration(200).start() } else { // 恢复原状 icon.animate().scaleX(1f).scaleY(1f).setDuration(200).start() text.animate().translationY(0f).setDuration(200).start() } item.isSelected = item == selectedItem } }
- 滚动隐藏/显示
给RecyclerView加滚动监听,实现向下滚动隐藏导航栏,向上滚动显示:
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() { override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { super.onScrolled(recyclerView, dx, dy) val navBar = findViewById<LinearLayout>(R.id.custom_bottom_nav) if (dy > 0) { // 向下滚动,隐藏导航栏 navBar.animate().translationY(navBar.height.toFloat()).setDuration(200).start() } else { // 向上滚动,显示导航栏 navBar.animate().translationY(0f).setDuration(200).start() } } })
内容的提问来源于stack exchange,提问作者Meital




