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

Jetpack Compose中Scaffold搭配NavHost后底部导航栏渲染异常问题求助

问题原因

该问题由三个Jetpack Compose Scaffold + Navigation适配错误共同导致:

  1. 底部导航的路由列表中包含了未在NavHost中注册的Add路由,你设计中Add功能对应悬浮操作按钮,底部导航的对应位置仅为占位,但是代码中依然给它配置了导航跳转逻辑,访问不存在的路由会导致导航状态异常,触发底部导航栏的绘制错误。
  2. 没有给NavHost应用Scaffold提供的内边距参数,NavHost默认会填充整个父布局,视觉上覆盖了底部导航栏,虽然底部栏的触摸逻辑依然有效,但是UI被遮挡。
  3. 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.10 01:42:04