Compose:如何让 IntrinsicSize.Max 与使用 fillToConstraint 的 ConstraintLayout 子级一起使用 Row

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

我想创建一个可滚动的

Row
,其中
Row
中每个项目的高度是最高项目的高度。在大多数情况下,人们会在
Modifier.height(intrinsicSize = IntrinsicSize.Max)
Row
上使用
modifier
。但是当项目是使用
ConstraintLayout
Dimension.fillToConstraints
s 时,这会不希望地拉伸
Row
的高度。

使用本文底部的测试代码...

当孩子们使用

TestBox
时,我得到了想要的行为......

当我将

TestBox
替换为使用
TestConstraintLayout
Modifier.fillToConstraints
时,我无法获得相同的结果。

测试代码

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.background
import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.constraintlayout.compose.ConstraintLayout
import androidx.constraintlayout.compose.Dimension

private val DEFAULT_PADDING = 16.dp
private const val LOREM_IPSUM = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent { TestScreen() }
    }
}

@Preview(backgroundColor = 0xFFFFFF, showBackground = true, widthDp = 360)
@Composable
fun TestScreen() {
    val itemWidth: Dp = LocalConfiguration.current.screenWidthDp.dp - (DEFAULT_PADDING * 2)
    Column(
        modifier = Modifier
            .fillMaxSize()
            .verticalScroll(rememberScrollState()),
    ) {
        Text(
            text = "Intrinsic Size + ConstraintLayout",
            fontSize = 20.sp,
            modifier = Modifier
                .wrapContentSize()
                .padding(top = DEFAULT_PADDING, start = DEFAULT_PADDING, end = DEFAULT_PADDING)
        )
        Text(
            text = "The goal of this demo is to create a Row where every item in the Row is the same height despite the fact that they might have differing heights. We are able to achieve this when the children are Boxes, but unable to achieve this when they are ConstraintLayouts",
            fontSize = 12.sp,
            modifier = Modifier
                .wrapContentSize()
                .padding(top = DEFAULT_PADDING, start = DEFAULT_PADDING, end = DEFAULT_PADDING)
        )

        Row(
            modifier = Modifier
                .fillMaxWidth()
                .wrapContentHeight()
                // This seems to break the TestConstraintLayout but not the TestBox
                .height(intrinsicSize = IntrinsicSize.Max)
                .horizontalScroll(rememberScrollState())
                .padding(top = DEFAULT_PADDING, start = DEFAULT_PADDING, end = DEFAULT_PADDING),
            horizontalArrangement = Arrangement.spacedBy(DEFAULT_PADDING)
        ) {
            // When using TestBox, we get the desired behavior.
            // But replace TestBox with TestConstraintLayout, and the Row height gets messed up.
            // Especially when we use fillToConstraints
            TestBox(
                text = LOREM_IPSUM.substring(200),
                modifier = Modifier
                    .width(itemWidth)
                    .fillMaxHeight()
            )
            TestBox(
                text = LOREM_IPSUM,
                modifier = Modifier
                    .width(itemWidth)
                    .fillMaxHeight()
            )
        }

        Text(
            text = "Bottom of Screen",
            fontSize = 12.sp,
            modifier = Modifier
                .wrapContentSize()
                .wrapContentHeight()
                .padding(vertical = DEFAULT_PADDING)
                .align(Alignment.CenterHorizontally),
        )
    }
}

@Preview(backgroundColor = 0xFFFFFF, showBackground = true, widthDp = 360)
@Composable
fun TestBox(modifier: Modifier = Modifier, text: String = LOREM_IPSUM) {
    Box(
        modifier = modifier
            .fillMaxWidth()
            .wrapContentHeight()
            .background(Color.LightGray)
            .then(modifier)
    ) {
        Text(
            text = text,
            modifier = Modifier
                .fillMaxWidth()
                .wrapContentHeight()
                .padding(DEFAULT_PADDING)
        )
    }
}

/**
 * Note that we are using a ConstraintLayout with minimal content for the sake of simplicity to demonstrate the issue.
 * In practice, the content of the ConstraintLayout would be more complicated.
 */
@Preview(backgroundColor = 0xFFFFFF, showBackground = true, widthDp = 360)
@Composable
fun TestConstraintLayout(modifier: Modifier = Modifier, text: String = LOREM_IPSUM) {
    ConstraintLayout(
        modifier = Modifier
            .fillMaxWidth()
            .wrapContentHeight()
            .background(Color.LightGray)
            .then(modifier)
    ) {
        val (textView) = createRefs()
        Text(
            text = text,
            modifier = Modifier.constrainAs(textView) {
                linkTo(
                    top = parent.top, topMargin = DEFAULT_PADDING,
                    bottom = parent.bottom, bottomMargin = DEFAULT_PADDING,
                    bias = 0f,
                )
                start.linkTo(parent.start, margin = DEFAULT_PADDING)
                end.linkTo(parent.end, margin = DEFAULT_PADDING)
                // Switching this to matchParent does makes a difference.
                // But, it does NOT keep the text top-aligned.
                // Instead, it centers the text vertically, which is not a desired behavior
                // Still, even if replacing fillToConstraints with matchParent worked in this test,
                // it wouldn't be a true solution bc with complex ConstraintLayout content, we
                // might want content with fillToConstraints
                width = Dimension.fillToConstraints
                height = Dimension.wrapContent
            }
        )
    }
}

我怎样才能让我的

ConstraintLayout
内的
Row
孩子们的行为方式与我的
Box
孩子们的行为方式相同(即孩子的身高是最高孩子的身高)?

android-jetpack-compose android-constraintlayout
© www.soinside.com 2019 - 2024. All rights reserved.