You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Android自定义底部导航栏:如何创建及调整指定底部导航栏?

嘿,我来一步步带你搞定Android自定义底部导航栏,不管你是想改官方组件的样式,还是做完全自定义的酷炫效果,都给你安排明白~


方案一:基于官方BottomNavigationView自定义(推荐,省心又规范)

官方组件自带了基础的导航逻辑,改改样式就能满足大部分需求,先从这个开始:

  1. 引入Material组件依赖
    在Module级的build.gradle里添加最新版本的Material库:
implementation "com.google.android.material:material:1.9.0"
  1. 编写布局文件
    在你的主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" />
  1. 定义导航菜单
    创建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>
  1. 自定义颜色与背景
  • 颜色选择器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>
  1. 处理选中事件
    在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
    }
}

方案二:完全自定义底部导航栏(自由度拉满)

如果官方组件满足不了你的特殊需求(比如要加自定义动画、特殊布局),那就自己搭一个:

  1. 编写自定义布局
    用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>
  1. 图标状态切换
    创建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>
  1. 处理点击与状态切换
    在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
}

进阶玩法:加动画与动态调整

想让导航栏更生动?试试这些技巧:

  1. 选中动画
    给选中的导航项加图标放大、文字上浮效果:
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
    }
}
  1. 滚动隐藏/显示
    给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

火山引擎 最新活动