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

如何在Android实现Pinterest风格底部悬浮可滑动标签导航栏?Compose/XML均可

Android 底部悬浮可滑动切换标签导航栏实现方案

方案1:Jetpack Compose 实现

核心思路

用HorizontalPager承载切换的页面内容,底部导航栏嵌套在HorizontalScroll容器中实现标签横向滑动,外层用带圆角和阴影的Card包裹实现悬浮效果,通过pagerState联动导航栏选中状态和页面滑动状态。

关键依赖

需引入Compose Material3及基础组件依赖,新版本官方已自带HorizontalPager无需额外引入三方库:

implementation "androidx.compose.material3:material3:1.2.0"
implementation "androidx.compose.foundation:foundation:1.6.0"

核心代码示例

  • 定义导航标签数据类
data class NavItem(val title: String, val icon: ImageVector)
  • 页面实现逻辑
@Composable
fun SlideBottomNavScreen() {
    val navItems = listOf(
        NavItem("首页", Icons.Default.Home),
        NavItem("分类", Icons.Default.Category),
        NavItem("推荐", Icons.Default.Star),
        NavItem("消息", Icons.Default.Message),
        NavItem("我的", Icons.Default.Person)
        // 可继续添加更多标签,超出屏幕宽度自动支持滑动
    )
    val pagerState = rememberPagerState(pageCount = { navItems.size })
    val coroutineScope = rememberCoroutineScope()

    Scaffold(
        containerColor = Color.Transparent,
        bottomBar = {
            // 用Card实现悬浮效果:圆角+阴影+底部边距
            Card(
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(horizontal = 16.dp, bottom = 16.dp)
                    .navigationBarsPadding(),
                shape = RoundedCornerShape(16.dp),
                elevation = CardDefaults.cardElevation(defaultElevation = 8.dp)
            ) {
                // 横向滚动容器承载导航标签
                HorizontalScroll(
                    modifier = Modifier.fillMaxWidth(),
                    state = rememberScrollState()
                ) {
                    Row(
                        modifier = Modifier
                            .fillMaxWidth()
                            .padding(horizontal = 8.dp, vertical = 12.dp),
                        horizontalArrangement = Arrangement.spacedBy(8.dp)
                    ) {
                        navItems.forEachIndexed { index, item ->
                            val isSelected = pagerState.currentPage == index
                            NavigationBarItem(
                                selected = isSelected,
                                onClick = {
                                    coroutineScope.launch {
                                        pagerState.animateScrollToPage(index)
                                    }
                                },
                                icon = { Icon(item.icon, contentDescription = item.title) },
                                label = { Text(item.title) },
                                colors = NavigationBarItemDefaults.colors(
                                    selectedIconColor = Color.Blue,
                                    selectedTextColor = Color.Blue,
                                    unselectedIconColor = Color.Gray,
                                    unselectedTextColor = Color.Gray
                                )
                            )
                        }
                    }
                }
            }
        }
    ) { innerPadding ->
        HorizontalPager(
            state = pagerState,
            modifier = Modifier
                .fillMaxSize()
                .padding(innerPadding)
        ) { page ->
            // 对应页面的内容实现
            Text(text = navItems[page].title + "页面", modifier = Modifier.fillMaxSize().wrapContentSize())
        }
    }
}

方案2:传统XML + Kotlin 实现

核心思路

布局用FrameLayout作为根容器,底部放置横向RecyclerView作为可滑动导航栏,加圆角、阴影、外边距实现悬浮效果,上层用ViewPager2承载切换页面,监听两个组件的状态实现联动。

布局代码示例

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/viewPager"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <!-- 悬浮底部导航栏 -->
    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/bottomNavRv"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"
        android:layout_marginHorizontal="16dp"
        android:layout_marginBottom="16dp"
        android:background="@drawable/bg_bottom_nav"
        android:elevation="8dp"
        android:clipToPadding="false" />

</FrameLayout>

导航栏背景bg_bottom_nav.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <solid android:color="@color/white" />
    <corners android:radius="16dp" />
</shape>

逻辑实现

  • 先实现导航标签的RecyclerView.Adapter,支持选中状态切换
  • 关联ViewPager2和RecyclerView的联动逻辑
class MainActivity : AppCompatActivity() {
    private val navItems = listOf("首页", "分类", "推荐", "消息", "我的")
    private lateinit var viewPager: ViewPager2
    private lateinit var bottomNavRv: RecyclerView
    private lateinit var navAdapter: NavAdapter
    private var currentSelectedPos = 0

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        viewPager = findViewById(R.id.viewPager)
        bottomNavRv = findViewById(R.id.bottomNavRv)

        // 配置底部导航RecyclerView为横向布局
        bottomNavRv.layoutManager = LinearLayoutManager(this, RecyclerView.HORIZONTAL, false)
        navAdapter = NavAdapter(navItems, currentSelectedPos) { pos ->
            // 点击标签切换页面
            viewPager.currentItem = pos
        }
        bottomNavRv.adapter = navAdapter

        // 配置ViewPager的Adapter
        viewPager.adapter = PageAdapter(this, navItems.size)

        // 监听页面滑动,同步导航选中状态
        viewPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
            override fun onPageSelected(position: Int) {
                super.onPageSelected(position)
                if (currentSelectedPos != position) {
                    navAdapter.updateSelected(position)
                    currentSelectedPos = position
                    // 自动滚动导航栏让选中标签居中
                    bottomNavRv.smoothScrollToPosition(position)
                }
            }
        })
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 20:30:03