【问题标题】:Best practice to remembering List State after navigation to another Composable using Jetpack Compose Navigation使用 Jetpack Compose Navigation 导航到另一个 Composable 后记住 List State 的最佳实践
【发布时间】:2021-08-15 22:47:15
【问题描述】:

当从 Composable A -> Composable B 导航时,说 Composable A 是一个向下滚动的惰性列表,而 Composable B 是一个惰性列表项详细信息屏幕。目前,惰性列表滚动位置没有被存储,当从 B 导航回 Composable A 时,列表从项目索引 0 开始。我们可以将它存储在 ViewModel 中,然后读取值,以及使用 rememberSaveable,但是,我不确定如何实现 rememberSaveable 以便在返回导航后滚动到保存的位置。

在遵循良好的代码实践时更倾向于使用哪种方法?

编辑: 我的问题源于从可组合 B 导航回 A 时未存储 listState。因此,如果我们滚动到底部并选择一个项目并查看其详细信息,当我们导航回列表时,它会滚动到顶部,而不是保存它的滚动状态。

我的可组合

        val listState = rememberLazyListState()
        val showTitle by remember {
            derivedStateOf {
                listState.firstVisibleItemIndex > 0
            }
        }

        onShowTitle(showTitle) // don't show title when first list element is visible


        LazyColumn(
            state = listState,
            contentPadding = PaddingValues(16.dp)
        ) {

            item {
                Text("Header 1", style = MaterialTheme.typography.h4)
            }
            item {
                Column(Modifier.fillMaxWidth()) {

                    CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.medium) {
                        Text(
                            "Description 1",
                            style = MaterialTheme.typography.subtitle1,
                            modifier = Modifier.padding(top = 8.dp)
                        )
                    }
                    Spacer(modifier = Modifier.height(48.dp))
                }
            }
            item {

                itemOfTheDay.value?.let { item->
                    ItemCardVertical(
                        item = item,
                        navigateToDetails = {
                            viewModel.selectItem(it)
                            navigateToDetails(it)
                        }
                    )
                    Spacer(modifier = Modifier.height(48.dp))
                }
            }
            item {
                Text("Header 2", style = MaterialTheme.typography.h5)

                Spacer(Modifier.size(16.dp))
            }
            item {


                StaggeredVerticalGrid(maxColumnWidth = 220.dp) {
                    items.value?.forEach { item->
                        ItemCard(item, navigateToDetails = {
                            viewModel.selectItem(it)
                            navigateToDetails(it)
                        })
                    }

我的导航图

 @Composable
    fun NavGraph(startDestination: String = "Items") {
        val navController = rememberNavController()

        val mainViewModel: MainViewModel = viewModel()
        NavHost(navController = navController, startDestination = startDestination) {

            navigation(route = "Items", startDestination = MAINSCREEN) {


                composable(MAINSCREEN) {
                   
                    MainScreen(mainViewModel,
                        navigateToDetails = { smoothie ->

                            navController.navigate(ITEMSDETAILSSCREEN)
                        }
                    )
                }
                composable(
                   ITEMDETAILSSCREEN
                ) {
      
                    ItemDetails(
                        viewModel = mainViewModel, modifier = Modifier
                            .fillMaxSize()
                            .navigationBarsPadding()
                    )
                }
            }
        }
    }

【问题讨论】:

  • rememberLazyListState 已在内部使用rememberSaveable,因此它已被正确保存和恢复。请包含您的代码
  • @ianhanniballake 我用代码示例更新了问题。
  • 上一个尝试使用navController.popBackStack()而不是navController.navigate( /*Route*/ )

标签: android kotlin android-jetpack-compose


【解决方案1】:

我会留下这个问题,以防其他人陷入我的困境,但代码按预期工作,我只是犯了一个愚蠢的错误。

我没有考虑异步图像加载时的高度变化,因此,由于列表状态小于返回到可组合导航时的屏幕高度,因此列表在可组合导航时不会位于其保存的位置。

但是,如果图像被加载到不改变其大小的静态容器中,那么在返回导航时,可组合项将正确显示保存的列表状态。

【讨论】:

    【解决方案2】:

    我认为这是compose中的一个错误,但我尝试了一种非常糟糕的方法来解决这个问题:

    1. 保存最后一次点击的indexscrollOffset
    2. 调用scrollToItem滚动到旧位置
    3. 不知道为什么,需要一定的延迟才能生效。它可能与我的代码状态有关。您可以尝试根据您的代码添加delay(1)
        LaunchedEffect(state) {
            delay(1)
            state.scrollToItem(viewModel.firstVisibleIndex, viewModel.firstVisibleIndexOffset)
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-02-21
      • 1970-01-01
      • 1970-01-01
      • 2014-05-05
      • 2021-09-16
      相关资源
      最近更新 更多