Jetpack Compose 如何实现向下滚动隐藏底部导航栏、向上滚动展示效果
实现步骤
1. 调整BottomBar组件,新增显隐控制参数并添加过渡动画
修改你的BottomBar代码,接收显隐状态参数,添加滑动+淡入淡出的过渡效果:
@Composable fun BottomBar( navController: NavController, isVisible: Boolean ) { val items = listOf( NavigationItem.Home, NavigationItem.Search ) // 底部栏偏移量动画:隐藏时向下移出屏幕 val bottomBarOffset by animateDpAsState( targetValue = if (isVisible) 0.dp else 56.dp, // 56.dp是Material Design标准底部导航栏高度 animationSpec = tween(durationMillis = 300) ) // 透明度动画:隐藏时逐步透明 val alpha by animateFloatAsState( targetValue = if (isVisible) 1f else 0f, animationSpec = tween(durationMillis = 300) ) BottomNavigation( backgroundColor = MaterialTheme.colors.DarkRed, contentColor = Color.White, modifier = Modifier .alpha(alpha) .offset(y = bottomBarOffset) ) { // 原有内部逻辑保持不变 val navBackStackEntry by navController.currentBackStackEntryAsState() val currentRoute = navBackStackEntry?.destination?.route items.forEach { item -> BottomNavigationItem( selected = currentRoute == item.route, icon = { Icon( imageVector = item.icon, contentDescription = "Icon", modifier = Modifier.size(28.dp) ) }, alwaysShowLabel = false, selectedContentColor = Color.White, unselectedContentColor = Color.White.copy(0.4f), onClick = { navController.navigate(item.route){ navController.graph.startDestinationRoute?.let{route -> popUpTo(route){ saveState = true } } launchSingleTop = true restoreState = true } } ) } } }
2. 在MainScreen中添加滚动监听逻辑,控制底部栏显隐
通过NestedScrollConnection监听全局滚动事件,根据滚动方向更新显隐状态:
@Composable fun MainScreen(){ val navController = rememberNavController() // 底部栏显隐状态 var isBottomBarVisible by remember { mutableStateOf(true) } // 嵌套滚动监听器,捕捉滚动方向 val nestedScrollConnection = remember { object : NestedScrollConnection { override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset { // 垂直滚动偏移量:大于0是向上滚动,小于0是向下滚动 val delta = available.y if (delta > 0 && !isBottomBarVisible) { // 向上滚动、底部栏隐藏时,显示底部栏 isBottomBarVisible = true } else if (delta < 0 && isBottomBarVisible) { // 向下滚动、底部栏显示时,隐藏底部栏 isBottomBarVisible = false } // 返回0表示不消费滚动事件,事件继续传递给子组件 return Offset.Zero } } } Scaffold( topBar = { ActionBar("Books") }, bottomBar = { BottomBar(navController = navController, isVisible = isBottomBarVisible) } ){ paddingValues -> NavigationGraph( navController = navController, modifier = Modifier .padding(paddingValues) // 绑定滚动监听器 .nestedScroll(nestedScrollConnection) ) } }
3. 可选适配:特殊页面强制显示底部栏
如果部分页面没有滚动布局(比如空白页、固定内容页),可以根据路由判断强制显示底部栏:
在MainScreen中获取当前路由,修改isBottomBarVisible的更新逻辑即可:
val navBackStackEntry by navController.currentBackStackEntryAsState() val currentRoute = navBackStackEntry?.destination?.route // 示例:搜索页不需要滚动隐藏,强制显示底部栏 val forceShowBottomBar = currentRoute == NavigationItem.Search.route // 滚动判断里加上强制显示的逻辑 if (delta > 0 && !isBottomBarVisible || forceShowBottomBar) { isBottomBarVisible = true } else if (delta < 0 && isBottomBarVisible && !forceShowBottomBar) { isBottomBarVisible = false }
注意事项
- 如果你的页面用
LazyColumn实现列表,不需要额外配置,默认支持嵌套滚动 - 如果用普通
Column,需要添加.verticalScroll(rememberScrollState())修饰符开启滚动能力 - 可以根据需要调整动画时长、底部栏高度参数适配你的设计需求
内容的提问来源于stack exchange,提问作者Mohammed Ziyad
相关产品推荐
相关产品推荐

