Jetpack Compose - 导航 - 脚手架 + NavHost 不工作

Posted

技术标签:

【中文标题】Jetpack Compose - 导航 - 脚手架 + NavHost 不工作【英文标题】:Jetpack Compose - Navigation - Scaffold + NavHost not working 【发布时间】:2021-10-05 06:47:31 【问题描述】:

所以我正在尝试使用 Jetpack Compose 创建一个应用程序。我有一个屏幕功能,其中包含一个没有顶部应用栏的脚手架、一个用于导航的底部栏和一个设置在底部栏中的浮动操作按钮。这一切都很好。

但是,当我将 NavHost 添加到脚手架的内容时,整个事情就停止了工作。如果没有 NavHost,一切都可以正常工作,而只是内容是屏幕的可组合功能。我尝试过为 NavHost 使用不同数量的可组合位置,不同的值用于填充全部无济于事。

What it looks like without a NavHost (i.e. how I want it to look)

代码:

sealed class Screen(val route: String, @DrawableRes val iconId: Int)
    object Home         : Screen("home", R.drawable.ic_home_24px)
    object Stats        : Screen("stats", R.drawable.ic_stats_icon)
    object Add          : Screen("add", R.drawable.ic_add_24px)
    object Programs     : Screen("programs", R.drawable.ic_programs_icon)
    object Exercises    : Screen("exercises", R.drawable.ic_exercises_icon)


@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,

    ) 
        HomeScreen()
//        NavHost(
//            navController = navController,
//            startDestination = Screen.Home.route
//        )
//            composable(Screen.Home.route) HomeScreen() 
//            composable(Screen.Stats.route) HomeScreen() 
//            composable(Screen.Programs.route) HomeScreen() 
//            composable(Screen.Exercises.route) HomeScreen() 
//        
    



@Composable
fun BottomBar(
    navController : NavController
)
    val items = listOf(
        Screen.Home,
        Screen.Stats,
        Screen.Add,
        Screen.Programs,
        Screen.Exercises
    )
    BottomAppBar(
        backgroundColor = OffWhite,
        cutoutShape = CircleShape,
        content = 
            BottomNavigation(
                backgroundColor = OffWhite,
                contentColor = OffWhite,
                modifier = Modifier
                    .height(100.dp)
            ) 
                val navBackStackEntry by navController.currentBackStackEntryAsState()
                val currentDestination = navBackStackEntry?.destination
                items.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 = 
                            //Navigate to selected screen
                            navController.navigate(screen.route) 
                                //Pop all from stack
                                popUpTo(navController.graph.findStartDestination().id)
                                    saveState = true
                                
                                //Avoid multiple copies of same screen on stack
                                launchSingleTop = true
                                //Restore state when reselecting a previously selected item
                                restoreState = true
                            
                        ,
                        alwaysShowLabel = false
                    )
                
            
        
    )

What it looks like with the NavHost. 该图像中的框是无法绘制的 BottomBar,因为可以单击每个框,这会将我带到 BottomBar、BottomNavigationItem、Icon 等。任何人都知道这里发生了什么,以及我能做什么要解决这个问题?谢谢

编辑:我想到的一件事是将 fun BottomBar -> BottomNavigationItem 中的“选定”布尔值更改为始终为真,只是为了查看空值是否影响它,但这并没有改变任何东西。

【问题讨论】:

【参考方案1】:

错误消息说 Preview 不支持 ViewModels 创建。因为,NavHost 创建视图模型,所以会出错。所以我做了一些预览脚手架和一些屏幕的操作,我将脚手架的内容分开了。

例子:

@Composable
fun MainApp(
    navController: NavController,
    content: @Composable (PaddingValues) -> Unit
) 
    StoreTheme 
        Scaffold(
            bottomBar =  BottomAppNavigationBar(navController) ,
            content = content
        )
    

在真实应用上:

...

val navController = rememberNavController()
MainApp(navController)  innerPadding ->
    NavHost(
        navController = navController,
        startDestination = BottomNavMenu.Screen1.route,
        modifier = Modifier.padding(innerPadding)
    ) 
        composable(...)  Screen1... 
        composable(...)  Screen2... 
    

...

预览:

@Preview(showBackground = true)
@Composable
fun MainAppPreview() 
    val navController = rememberNavController()
    
    MainApp(navController) 
        Screen1(navController)
    

【讨论】:

是的,我昨天发现了,谢谢。我在预览中也做同样的事情,只是想测试导航是否正常工作:(希望他们很快实现这一点【参考方案2】:

原来我的工作室主题隐藏了错误通知。更改主题后显示

java.lang.IllegalStateException:预览版不支持创建 ViewModels

所以我想我需要在手机中敲击它来测试。

【讨论】:

以上是关于Jetpack Compose - 导航 - 脚手架 + NavHost 不工作的主要内容,如果未能解决你的问题,请参考以下文章

带有浮动顶栏的脚手架(Jetpack Compose)

Jetpack Compose中的导航路由

jetpack compose 接收返回参数

Jetpack Compose:拖动 MapView 时会打开 Scaffold 抽屉

BottomNavigationBar 中的 Jetpack Compose 导航问题

如何处理 Jetpack Compose 中的导航?