简体   繁体   English

LazyColumn 内的 LazyHorizontalGrid

[英]LazyHorizontalGrid inside LazyColumn

I have a LazyColumn and inside it I want to display a horizontal row with two columns, so I was trying LazyHorizontalGrid to achieve it.我有一个 LazyColumn 并且在它里面我想显示一个有两列的水平行,所以我正在尝试 LazyHorizontalGrid 来实现它。 But my application crashes with the exception - IllegalArgumentException: LazyHorizontalGrid's height should be bound by parent .但是我的应用程序崩溃并出现异常 - IllegalArgumentException: LazyHorizontalGrid's height should be bound by parent Below is my code what I am using, can anyone please help to fix it or any other way through which I can make a row have two columns.下面是我正在使用的代码,任何人都可以帮助修复它或任何其他方式,通过它我可以使一行有两列。

@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])
                    }
                }
            }
        }
    }
}

All you need to calculate the Grid's height beforehand.所有你需要事先计算网格的高度。

    @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))
                    }
                }
            }
        }
    }
}

LazyList exceptions with dimensions occur when you try to measure respective dimension with Constraints.Infinity .当您尝试使用Constraints.Infinity测量相应维度时,会出现带有维度的LazyList异常。 I explained about in this answer how Constraints are applied based on modifiers, Modifier.scroll() .在这个答案中解释了如何基于修饰符Modifier.scroll()应用约束。 Also, using a scrollable parent Composable like LazyColumn creates Constraints with infinite height , LazyRow creates Constraints with infinite width .此外,使用像LazyColumn这样的可滚动父 Composable 创建具有无限高度的 Constraints, LazyRow创建具有无限宽度的 Constraints。

You can use Modifier.height(maxHeight) with maxHeight from您可以将 Modifier.height(maxHeight) 与 maxHeight 从

You can use Modifier.height(maxHeight) or Modifier.layout{} and constrain max height to screen height or selected height in px.您可以使用Modifier.height(maxHeight)Modifier.layout{}并将最大高度限制为屏幕高度或以像素为单位的选定高度。 Constraints return dimensions in px that is to be used with layout function. Getting Constrains height from parent by wrapping it with BoxWithConstraints returns non-infinite height约束返回将与布局 function 一起使用的以 px 为单位的尺寸。通过用 BoxWithConstraints 包装它从父级获取约束高度返回非无限高度

@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
                           // .height(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])
                            }
                        }
                    }
                }
            }
        }
    }
}

The example above creates a LazyHorizontalGrid with full height of screen, i added an Image as another element to show that grid covers parent height.上面的示例创建了一个具有全屏高度的 LazyHorizontalGrid,我添加了一个Image作为另一个元素来显示网格覆盖父级高度。

The important thing here is how you set maxHeight for Constraints in这里重要的是你如何为 Constraints 设置 maxHeight

constraints.copy(maxHeight = parentConstraints.maxHeight)

If you want grid to match item size then you should measure size of an item如果您希望网格与项目大小相匹配,那么您应该测量项目的大小

using rowCount * itemHeight + (rowCount-1)* verticalSpacingInPx .使用rowCount * itemHeight + (rowCount-1)* verticalSpacingInPx

constraints.copy(maxHeight = 600f) for instance. constraints.copy(maxHeight = 600f)例如。

If you don't know the height of the item you should use Modifier.onSizeChanged or as in this answer SubcomposeLayout or Layout如果您不知道项目的高度,您应该使用 Modifier.onSizeChanged 或在此答案中使用SubcomposeLayoutLayout

How to get exact size without recomposition? 如何在不重组的情况下获得准确的尺寸?

And using Text as dependent item we can do it as并使用 Text 作为依赖项,我们可以这样做

@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 that uses Text height and spacing to calculate height for LazyHorizontal Grid使用文本高度和间距计算 LazyHorizontal Grid 高度的 SubComposeLayout

@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)
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM