Jetpack 在可滚动列中编写 LazyColumn

Jetpack Compose LazyColumn inside Scrollabe Column

这是我的情况:我必须在我的应用程序中显示从 API 收到的记录的详细信息。在此视图中,我可能需要也可能不需要根据字段显示来自另一个视图模型的一些数据。

这是我的代码:

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ViewDetail(viewModel: MainViewModel, alias: String?, otherViewModel: OtherViewModel) {
    viewModel.get(alias)

    Scaffold {
        val isLoading by viewModel.isLoading.collectAsState()
        val details by viewModel.details.collectAsState()

        when {
            isLoading -> LoadingUi()
            else -> Details(details, otherViewModel)
        }
    }
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun Details(details: Foo?, otherViewModel: OtherViewModel) {
    details?.let { sh ->
        val scrollState = rememberScrollState()

        Column(
            modifier = Modifier
                .fillMaxSize()
                .verticalScroll(scrollState),
        ) {
            Text(sh.title, fontSize = 24.sp, lineHeight = 30.sp)

            Text(text = sh.description)

            if (sh.other.isNotEmpty()) {
                otherViewModel.load(sh.other)
                val others by otherViewModel.list.collectAsState()

                Others(others)
            }
        }
    }
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun Others(others: Flow<PagingData<Other>>) {
    val items: LazyPagingItems<Other> = others.collectAsLazyPagingItems()

    LazyColumn(
        modifier = Modifier
            .fillMaxWidth()
            .wrapContentHeight(),
        contentPadding = PaddingValues(16.dp),
    ) {
        items(items = items) { item ->
            if (item != null) {
                Text(text = item.title, fontSize = 24.sp)

                Spacer(modifier = Modifier.height(4.dp))

                Text(text = item.description)
            }
        }

        if (items.itemCount == 0) {
            item { EmptyContent() }
        }
    }
}

这里的所有描述都可能很长,无论是在主要详细信息正文中还是在其他(如果存在)中,这就是请求滚动行为的原因。

问题:我收到此错误:

Vertically scrollable component was measured with an infinity maximum height constraints, which is disallowed. One of the common reasons is nesting layouts like LazyColumn and Column(Modifier.verticalScroll()).

我希望 LazyColumn 中的 .wrapContentHeight() 可以解决问题,但无济于事。

这样做正确吗?

上下文:所有包都更新到 maven 上可用的最新版本

您可以使用如下系统

@Composable
fun Test() {
    Box(Modifier.systemBarsPadding()) {
        Details()
    }
}

@Composable
fun Details() {
    LazyColumn(Modifier.fillMaxSize()) {
        item {
            Box(Modifier.background(Color.Cyan).padding(16.dp)) {
                Text(text = "Hello World!")
            }
        }
        item {
            Box(Modifier.background(Color.Yellow).padding(16.dp)) {
                Text(text = "Another data")
            }
        }
        item {
            Others()
        }
    }
}

@Composable
fun Others() {
    val values = MutableList(50) { it }

    values.forEach {
        Box(
            Modifier
                .fillMaxWidth()
                .padding(16.dp)
        ) {
            Text(text = "Value = $it")
        }
    }
}

滚动的结果是:

这里的主要想法是将您的 ColumnLazyColumn 合并。

由于您的代码不可运行,我给出了更多的伪代码,理论上应该可以运行。

直接从可组合构建器调用 otherViewModel.load(sh.other) 也是错误的。根据thinking in compose, to get best performance your view should be side effects free. To solve this issue Compose have special side effect functions。现在你的代码将在每次重组时被调用。

if (sh.other.isNotEmpty()) {
    LaunchedEffect(Unit) {
        otherViewModel.load(sh.other)
    }
}
val others by otherViewModel.list.collectAsState()

LazyColumn(
    modifier = Modifier
        .fillMaxSize()
        .wrapContentHeight(),
    contentPadding = PaddingValues(16.dp),
) {
    item {
        Text(sh.title, fontSize = 24.sp, lineHeight = 30.sp)

        Text(text = sh.description)
    }
    
    items(items = items) { item ->
        if (item != null) {
            Text(text = item.title, fontSize = 24.sp)

            Spacer(modifier = Modifier.height(4.dp))

            Text(text = item.description)
        }
    }

    if (items.itemCount == 0) {
        item { EmptyContent() }
    }
}