Jetpack Compose中Scaffold搭配NavHost后底部导航栏渲染异常问题求助
问题原因
该问题由三个Jetpack Compose Scaffold + Navigation适配错误共同导致:
- 底部导航的路由列表中包含了未在NavHost中注册的
Add路由,你设计中Add功能对应悬浮操作按钮,底部导航的对应位置仅为占位,但是代码中依然给它配置了导航跳转逻辑,访问不存在的路由会导致导航状态异常,触发底部导航栏的绘制错误。 - 没有给NavHost应用Scaffold提供的内边距参数,NavHost默认会填充整个父布局,视觉上覆盖了底部导航栏,虽然底部栏的触摸逻辑依然有效,但是UI被遮挡。
- BottomAppBar内部嵌套的BottomNavigation被写死了100dp高度,和BottomAppBar自身的测量逻辑冲突,导致内部图标绘制异常。
修复方案
步骤1:调整底部导航的占位逻辑
将Add从可跳转的导航列表中移除,在底部导航中间插入对应宽度的占位控件,避免访问未注册路由:
@Composable fun BottomBar( navController : NavController ){ // 移除Add路由,只保留可跳转的4个页面 val items = listOf( Screen.Home, Screen.Stats, Screen.Programs, Screen.Exercises ) BottomAppBar( backgroundColor = OffWhite, cutoutShape = CircleShape, // 把高度设置到BottomAppBar上,不要给内部的BottomNavigation写死高度 modifier = Modifier.height(100.dp) ) { BottomNavigation( backgroundColor = OffWhite, modifier = Modifier.fillMaxHeight() ) { val navBackStackEntry by navController.currentBackStackEntryAsState() val currentDestination = navBackStackEntry?.destination // 渲染前两个导航项 items.take(2).forEach { screen -> val selected = currentDestination?.hierarchy?.any { it.route == screen.route } == true BottomNavigationItem( icon = { val iconSize = if (selected) 32.dp else 20.dp Icon( painter = painterResource(id = screen.iconId), contentDescription = screen.route, tint = Blue, modifier = Modifier .padding(12.dp) .size(iconSize) ) }, selected = selected, onClick = { navController.navigate(screen.route) { popUpTo(navController.graph.findStartDestination().id){ saveState = true } launchSingleTop = true restoreState = true } }, alwaysShowLabel = false ) } // 中间FAB占位,和Add原来的位置对应 Spacer(modifier = Modifier.weight(1f)) // 渲染后两个导航项 items.takeLast(2).forEach { screen -> val selected = currentDestination?.hierarchy?.any { it.route == screen.route } == true BottomNavigationItem( icon = { val iconSize = if (selected) 32.dp else 20.dp Icon( painter = painterResource(id = screen.iconId), contentDescription = screen.route, tint = Blue, modifier = Modifier .padding(12.dp) .size(iconSize) ) }, selected = selected, onClick = { navController.navigate(screen.route) { popUpTo(navController.graph.findStartDestination().id){ saveState = true } launchSingleTop = true restoreState = true } }, alwaysShowLabel = false ) } } } }
步骤2:给NavHost应用Scaffold内边距
在Scaffold的content区域,给NavHost添加padding参数,避让底部导航栏:
@ExperimentalFoundationApi @Preview @Composable fun Screen(){ val navController = rememberNavController() Scaffold( backgroundColor = OffWhite, bottomBar = { BottomBar(navController = navController) }, floatingActionButton = { FloatingActionButton( onClick = {}, shape = CircleShape, backgroundColor = Blue ) { Icon( painter = painterResource(id = R.drawable.ic_add_24px), contentDescription = "Add", tint = OffWhite, modifier = Modifier .padding(12.dp) .size(32.dp) ) } }, isFloatingActionButtonDocked = true, floatingActionButtonPosition = FabPosition.Center, ) { innerPadding -> // 应用内边距,避免内容覆盖底部栏 NavHost( navController = navController, startDestination = Screen.Home.route, modifier = Modifier.padding(innerPadding) ){ composable(Screen.Home.route){ HomeScreen() } composable(Screen.Stats.route){ HomeScreen() } composable(Screen.Programs.route){ HomeScreen() } composable(Screen.Exercises.route){ HomeScreen() } } } }
修改完成后即可恢复正常的底部导航绘制和导航逻辑。
内容的提问来源于stack exchange,提问作者Chris Wright
相关产品推荐
相关产品推荐

