我有一个 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])
}
}
}
}
}
}
您需要预先计算网格的高度。
@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
测量相应尺寸时,会出现
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)
}
}
}
只需为 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将开始嵌套滚动。 如果您确实想确保不需要嵌套滚动,则“丑陋”的解决方法是设置一个非常大的最大高度。