如何在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
相关产品推荐
相关产品推荐

