You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android中BottomNavigation中间放置FAB/ImageButton的实现方法咨询

没问题!要实现这种中间带操作按钮的BottomNavigation,我给你两种实用方案,一步步来就能搞定:

Bottom Navigation with FAB on middle

方案一:官方组件快速实现(CoordinatorLayout + BottomNavigationView + FAB)

这个方案用Google官方的Material组件组合,简单省心,适合大多数场景:

  1. 编写布局文件
    用CoordinatorLayout作为根布局,把BottomNavigationView和FAB放在底部,通过锚点和偏移量让FAB嵌在导航栏中间:
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <!-- 主内容容器,用来放Fragment或其他页面内容 -->
    <FrameLayout
        android:id="@+id/main_content_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@id/bottom_navigation"/>

    <!-- 底部导航栏 -->
    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/bottom_navigation"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"
        android:background="@color/white"
        app:menu="@menu/bottom_nav_menu"/>

    <!-- 中间的FAB按钮 -->
    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:id="@+id/middle_fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/ic_add"
        app:layout_anchor="@id/bottom_navigation"
        app:layout_anchorGravity="center_horizontal|top"
        android:layout_marginTop="-32dp"/> <!-- 偏移量设为FAB高度的一半,刚好嵌在导航栏中间 -->

</androidx.coordinatorlayout.widget.CoordinatorLayout>
  1. 配置导航菜单
    在res/menu/bottom_nav_menu.xml里添加菜单选项,注意给中间的FAB留空位置(比如设置一个不可点击的空item):
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/nav_home"
        android:icon="@drawable/ic_home"
        android:title="首页"/>
    <item
        android:id="@+id/nav_search"
        android:icon="@drawable/ic_search"
        android:title="搜索"/>
    <!-- 空item占位置,避免导航栏选项挤在一起 -->
    <item
        android:id="@+id/nav_placeholder"
        android:icon="@android:color/transparent"
        android:title=""
        android:enabled="false"/>
    <item
        android:id="@+id/nav_profile"
        android:icon="@drawable/ic_profile"
        android:title="我的"/>
</menu>
  1. 处理点击逻辑
    在Activity或Fragment里给导航栏和FAB设置点击事件,同时跳过中间的空item:
val bottomNav = findViewById<BottomNavigationView>(R.id.bottom_navigation)
val middleFab = findViewById<FloatingActionButton>(R.id.middle_fab)

// 底部导航栏选中事件
bottomNav.setOnItemSelectedListener { menuItem ->
    when (menuItem.itemId) {
        R.id.nav_home -> {
            // 切换到首页Fragment或执行首页逻辑
            true
        }
        R.id.nav_search -> {
            // 切换到搜索Fragment或执行搜索逻辑
            true
        }
        R.id.nav_profile -> {
            // 切换到个人中心Fragment或执行个人中心逻辑
            true
        }
        else -> false // 忽略中间的空item
    }
}

// 中间FAB点击事件
middleFab.setOnClickListener {
    // 执行你需要的操作,比如打开添加页面、触发提交等
}
方案二:自定义布局实现高度定制

如果需要更灵活的样式(比如自定义按钮形状、带文字的按钮),可以直接写一个自定义的底部导航布局:

  1. 编写自定义底部布局
    用LinearLayout平分宽度,中间的按钮单独用容器包裹并向上偏移:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="bottom"
    android:background="@color/white"
    android:orientation="horizontal"
    android:paddingVertical="8dp"
    android:elevation="8dp">

    <!-- 首页按钮 -->
    <ImageView
        android:id="@+id/btn_home"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:src="@drawable/ic_home"
        android:scaleType="centerInside"
        android:padding="8dp"/>

    <!-- 搜索按钮 -->
    <ImageView
        android:id="@+id/btn_search"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:src="@drawable/ic_search"
        android:scaleType="centerInside"
        android:padding="8dp"/>

    <!-- 中间自定义按钮容器 -->
    <LinearLayout
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="wrap_content"
        android:gravity="center">

        <ImageButton
            android:id="@+id/btn_middle_action"
            android:layout_width="64dp"
            android:layout_height="64dp"
            android:src="@drawable/ic_add"
            android:background="@drawable/custom_button_bg"
            android:layout_marginTop="-32dp"
            android:scaleType="centerInside"/>
    </LinearLayout>

    <!-- 通知按钮 -->
    <ImageView
        android:id="@+id/btn_notify"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:src="@drawable/ic_notify"
        android:scaleType="centerInside"
        android:padding="8dp"/>

    <!-- 个人中心按钮 -->
    <ImageView
        android:id="@+id/btn_profile"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:src="@drawable/ic_profile"
        android:scaleType="centerInside"
        android:padding="8dp"/>

</LinearLayout>
  1. 自定义按钮背景
    在res/drawable/custom_button_bg.xml里写一个圆形背景:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval">
    <solid android:color="@color/teal_200"/> <!-- 设置你想要的按钮颜色 -->
    <size android:width="64dp" android:height="64dp"/>
</shape>
  1. 处理点击与选中状态
    在代码里给每个按钮设置点击事件,同时处理选中时的图标颜色切换:
val btnHome = findViewById<ImageView>(R.id.btn_home)
val btnSearch = findViewById<ImageView>(R.id.btn_search)
val btnMiddle = findViewById<ImageButton>(R.id.btn_middle_action)
val btnNotify = findViewById<ImageView>(R.id.btn_notify)
val btnProfile = findViewById<ImageView>(R.id.btn_profile)

// 首页按钮点击
btnHome.setOnClickListener {
    resetNavIconColors()
    btnHome.setColorFilter(ContextCompat.getColor(this, R.color.teal_200))
    // 切换首页内容
}

// 搜索按钮点击
btnSearch.setOnClickListener {
    resetNavIconColors()
    btnSearch.setColorFilter(ContextCompat.getColor(this, R.color.teal_200))
    // 切换搜索内容
}

// 中间按钮点击
btnMiddle.setOnClickListener {
    // 执行自定义操作
}

// 通知按钮点击
btnNotify.setOnClickListener {
    resetNavIconColors()
    btnNotify.setColorFilter(ContextCompat.getColor(this, R.color.teal_200))
    // 切换通知内容
}

// 个人中心按钮点击
btnProfile.setOnClickListener {
    resetNavIconColors()
    btnProfile.setColorFilter(ContextCompat.getColor(this, R.color.teal_200))
    // 切换个人中心内容
}

// 重置所有导航图标为默认颜色
private fun resetNavIconColors() {
    val defaultColor = ContextCompat.getColor(this, R.color.grey_600)
    btnHome.setColorFilter(defaultColor)
    btnSearch.setColorFilter(defaultColor)
    btnNotify.setColorFilter(defaultColor)
    btnProfile.setColorFilter(defaultColor)
}

这两种方案都能完美实现你要的效果,第一种适合快速开发,第二种适合需要高度定制按钮样式的场景~

内容的提问来源于stack exchange,提问作者Sanath

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 06:36:20