LazyColumn 内的 LazyHorizontalGrid

问题描述 投票:0回答:3

我有一个 LazyColumn,在其中我想显示一个包含两列的水平行,所以我尝试使用 LazyHorizontalGrid 来实现它。但我的应用程序崩溃了,但有例外 -

IllegalArgumentException: LazyHorizontalGrid's height should be bound by parent
。 下面是我正在使用的代码,任何人都可以帮忙修复它或通过任何其他方式使一行有两列。

@Composable
fun HomeItem1() {
    Surface(modifier = Modifier.nestedScroll(rememberViewInteropNestedScrollConnection())) {
        LazyColumn {
            //other contents
            item {
                LazyHorizontalGrid(
                    rows = GridCells.Fixed(3),
                    horizontalArrangement = Arrangement.spacedBy(16.dp),
                    verticalArrangement = Arrangement.spacedBy(16.dp)
                ) {
                    items(arrayList.size) {
                        Text(arrayList[it])
                    }
                }
            }
        }
    }
}
android kotlin android-jetpack-compose android-jetpack
3个回答
4
投票

您需要预先计算网格的高度。

    @Composable
    fun HomeItem1() {
        Surface(modifier = Modifier.nestedScroll(rememberViewInteropNestedScrollConnection())) {
        LazyColumn {
            //other contents
            item {
                LazyHorizontalGrid(
                    modifier = Modifier.height(176.dp), // itemHeight * rowCount + verticalSpacing * (rowCount - 1)
                    rows = GridCells.Fixed(3),
                    horizontalArrangement = Arrangement.spacedBy(16.dp),
                    verticalArrangement = Arrangement.spacedBy(16.dp)
                ) {
                    items(arrayList.size) {
                        Text(arrayList[it], modifier = Modifier.height(48.dp))
                    }
                }
            }
        }
    }
}

2
投票
当您尝试使用

LazyList

 测量相应尺寸时,会出现
Constraints.Infinity
尺寸
异常。我解释了在此答案中如何基于修饰符应用约束,
Modifier.scroll()
。此外,使用像
LazyColumn
这样的可滚动父级可组合项会创建 具有无限高度的约束
LazyRow
会创建具有无限宽度的约束

您可以将 Modifier.heightIn(maxHeight) 与 maxHeight 一起使用,这意味着如果内容高度之和大于其他项目未使用的其余高度,则最多可以测量或分配此 LazyColumn 的父级总高度。

您可以使用

Modifier.heightIn(maxHeight)
Modifier.layout{}
并将最大高度限制为屏幕高度或选定的高度(以像素为单位)。约束返回要与布局函数一起使用的尺寸(以 px 为单位)。通过使用 BoxWithConstraints 包装从父级获取 Constrains 高度会返回非无限高度

@Composable
private fun Sample() {

    val arrayList = remember {
        mutableStateListOf<String>().apply {
            repeat(40) {
                add("Item $it")
            }
        }
    }


    Column(
        modifier = Modifier
            .border(4.dp, Color.Green)
            .fillMaxSize()

    ) {

        BoxWithConstraints {

            val parentConstraints = this.constraints
            val maxHeight = this.maxHeight

            LazyColumn {
                //other contents
                item {
                    Image(
                        modifier = Modifier
                            .height(200.dp)
                            .fillMaxWidth(),
                        painter = painterResource(id = R.drawable.landscape2),
                        contentDescription = null,
                        contentScale = ContentScale.FillBounds
                    )
                }
                item {

                    LazyHorizontalGrid(
                        modifier = Modifier
                            .border(2.dp, Color.Red)
                           // Alternative 1
                           // .heightIn(maxHeight)
                           // Alternative 2
                            .layout { measurable, constraints ->
                                val placeable = measurable.measure(
                                    constraints.copy(maxHeight = parentConstraints.maxHeight)
                                )

                                layout(placeable.width, placeable.height) {
                                    placeable.placeRelative(0, 0)
                                }
                            },
                        rows = GridCells.Fixed(3),
                        horizontalArrangement = Arrangement.spacedBy(16.dp),
                        verticalArrangement = Arrangement.spacedBy(16.dp)
                    ) {
                        items(arrayList.size) {
                            Box(
                                modifier = Modifier
                                    .shadow(2.dp, RoundedCornerShape(8.dp))
                                    .background(Color.White)
                                    .aspectRatio(1f)
                                    .padding(2.dp)
                            ) {
                                Text(arrayList[it])
                            }
                        }
                    }
                }
            }
        }
    }
}

上面的示例创建了一个具有屏幕全高的 LazyHorizontalGrid,我添加了一个

Image
作为另一个元素以显示网格覆盖父级高度。

这里重要的是如何设置约束的 maxHeight

constraints.copy(maxHeight = parentConstraints.maxHeight)

如果您希望网格匹配项目尺寸,那么您应该测量项目的尺寸

使用

rowCount * itemHeight + (rowCount-1)* verticalSpacingInPx

例如

constraints.copy(maxHeight = 600f)

如果您不知道项目的高度,则应该使用 Modifier.onSizeChanged 或如本答案所示

SubcomposeLayout
Layout

如何在不重新组合的情况下获得精确尺寸?

并使用文本作为依赖项,我们可以这样做

@Composable
private fun Sample2() {

    val arrayList = remember {
        mutableStateListOf<String>().apply {
            repeat(40) {
                add("Item $it")
            }
        }
    }

    val mainComposable = @Composable {
        Box(
            modifier = Modifier
                .shadow(2.dp, RoundedCornerShape(8.dp))
                .background(Color.White)
                .size(80.dp)
                .padding(2.dp)
        ) {
            Text(arrayList[0])
        }
    }

    Column(
        modifier = Modifier
            .border(4.dp, Color.Green)
            .fillMaxSize()

    ) {

        DimensionSubcomposeLayout(
            rowCount = 3,
            verticalSpacing = 16.dp,
            mainContent = {
                mainComposable()
            }
        ) { size: Dp ->
            LazyColumn {

                //other contents
                item {
                    Image(
                        modifier = Modifier
                            .height(200.dp)
                            .fillMaxWidth(),
                        painter = painterResource(id = R.drawable.landscape2),
                        contentDescription = null,
                        contentScale = ContentScale.FillBounds
                    )
                }

                item {
                    LazyHorizontalGrid(
                        modifier = Modifier
                            .height(size)
                            .border(2.dp, Color.Red),
                        rows = GridCells.Fixed(3),
                        horizontalArrangement = Arrangement.spacedBy(16.dp),
                        verticalArrangement = Arrangement.spacedBy(16.dp)
                    ) {
                        items(arrayList.size) {
                            Box(
                                modifier = Modifier
                                    .shadow(2.dp, RoundedCornerShape(8.dp))
                                    .background(Color.White)
                                    .size(80.dp)
                                    .padding(2.dp)
                            ) {
                                Text(arrayList[it])
                            }
                        }
                    }
                }
            }
        }
    }
}

SubComposeLayout 使用文本高度和间距来计算 LazyHorizontal Grid 的高度

@Composable
fun DimensionSubcomposeLayout(
    modifier: Modifier = Modifier,
    rowCount: Int,
    verticalSpacing: Dp = 0.dp,
    mainContent: @Composable () -> Unit,
    dependentContent: @Composable (Dp) -> Unit
) {

    val density = LocalDensity.current
    val verticalSpacingPx = density.run { verticalSpacing.toPx() }

    SubcomposeLayout(
        modifier = modifier
    ) { constraints: Constraints ->

        // Subcompose(compose only a section) main content and get Placeable
        val mainPlaceable = subcompose(SlotsEnum.Main, mainContent)
            .map {
                it.measure(constraints)
            }
            .first()


        // Get max width and height of main component

        val maxHeight = mainPlaceable.height * rowCount + (rowCount - 1) * verticalSpacingPx

        val dpSize = with(density.density) {
            maxHeight.toDp()
        }

        val dependentPlaceable = subcompose(SlotsEnum.Dependent) {
            dependentContent(dpSize)
        }
            .map { measurable: Measurable ->
                measurable.measure(constraints)
            }
            .first()

        layout(dependentPlaceable.width, dependentPlaceable.height) {
            dependentPlaceable.placeRelative(0, 0)
        }
    }
}

0
投票

只需为 LazyHorizontalGrid 设置固定高度或设置最大高度。

    @Composable
    fun HomeItem1() {
    Surface(modifier = Modifier.nestedScroll(rememberViewInteropNestedScrollConnection())) {
        LazyColumn {
            //other contents
            item {
                LazyHorizontalGrid(
                    modifier = Modifier.heightIn(max=200.dp),
                    rows = GridCells.Fixed(3),
                    horizontalArrangement = Arrangement.spacedBy(16.dp),
                    verticalArrangement = Arrangement.spacedBy(16.dp)
                ) {
                    items(arrayList.size) {
                        Text(arrayList[it])
                    }
                }
            }
        }
    }
}

如果高度增加超过200.dp,则Grid将开始嵌套滚动。 如果您确实想确保不需要嵌套滚动,则“丑陋”的解决方法是设置一个非常大的最大高度。

© www.soinside.com 2019 - 2024. All rights reserved.