Jetpack Compose 中不同类型的宽度

7

我正在使用Jetpack Compose的文本框(textfield)。我想要构建类似于这样的东西:

enter image description here

TextField(
            value = value,
            onValueChange = {
                value = it
            },
            modifier = Modifier
                .requiredWidth(56.dp)
                .padding(10.dp),
            colors = TextFieldDefaults.textFieldColors(
                backgroundColor = OffWhite,
                focusedIndicatorColor = TealLight,
                cursorColor = TealLight
            )
        )

情景1

当我尝试这个时

 .requiredWidth(56.dp)

或者

.width(56.dp)

它在设计中看起来像这样

enter image description here

场景2

当我尝试这样做时

.widthIn(min = 56.dp)

它看起来像这样

enter image description here

场景3

当我尝试这样做时

.fillMaxWidth()

它占据了整个屏幕宽度。
所以我的问题是哪种情况下使用哪种?在我的情况下最好的属性是什么?
3个回答

14

在Jetpack Compose中,组合元素或子组合元素的尺寸使用约束设置,这是一组尺寸和边界或有限标志。而Modifier.requiredX用于强制大小,但如果约束不在父级限制范围内,则可能会轻易破坏您的布局。

widthInrequiredWidthIn之间的区别在于前者遵守其之前的尺寸修饰符或最大父级尺寸,而后者可以强制约束

/**
 * Create a [Constraints]. [minWidth] and [minHeight] must be positive and
 * [maxWidth] and [maxHeight] must be greater than or equal to [minWidth] and [minHeight],
 * respectively, or [Infinity][Constraints.Infinity].
 */
@Stable
fun Constraints(
    minWidth: Int = 0,
    maxWidth: Int = Constraints.Infinity,
    minHeight: Int = 0,
    maxHeight: Int = Constraints.Infinity
): Constraints {
    require(maxWidth >= minWidth) {
        "maxWidth($maxWidth) must be >= than minWidth($minWidth)"
    }
    require(maxHeight >= minHeight) {
        "maxHeight($maxHeight) must be >= than minHeight($minHeight)"
    }
    require(minWidth >= 0 && minHeight >= 0) {
        "minWidth($minWidth) and minHeight($minHeight) must be >= 0"
    }
    return Constraints.createConstraints(minWidth, maxWidth, minHeight, maxHeight)
}

在测量期间,基于约束,宽度和高度被分配给组合成为可放置对象

在下面的示例中,当TextField没有具有固定大小的父级时,它会增长到最大宽度。如果设置了小于TextField的固定大小,并使用Modifier.widthIn(),则TextField将设置为父级宽度,而Modifier.requiredWidthIn()则会跳出父级,直到(TextField大小 - 父级大小)/ 2。

enter image description here

@Composable
private fun TextFieldSamples() {

    Column(
        modifier = Modifier
            .padding(20.dp).border(2.dp, Color.Cyan)
    ) {

        var text1 by remember { mutableStateOf("") }

        Column(modifier = Modifier) {
            TextField(
                modifier = Modifier
                    .border(2.dp, Color.Green)
                    .widthIn(56.dp),
                value = text1,
                onValueChange = { text1 = it }
            )

            TextField(
                modifier = Modifier
                    .border(2.dp, Color.Red)
                    .requiredWidthIn(56.dp),
                value = text1, onValueChange = { text1 = it })
        }

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

        var text2 by remember { mutableStateOf("") }

        Column(modifier = Modifier.width(50.dp)) {
            TextField(
                modifier = Modifier
                    .border(2.dp, Color.Green)
                    .widthIn(56.dp),
                value = text2, onValueChange = { text2 = it })

            TextField(
                modifier = Modifier
                    .border(2.dp, Color.Red)
                    .requiredWidthIn(56.dp),
                value = text2, onValueChange = { text2 = it })
        }
    }
}

尺寸修饰符

Modifier.width/height()

返回具有固定约束或具有相等的minWidth/Height和maxWidth/Height的约束。 因此,子组件受到此约束的限制。

Modifier.fillmaxWidth/Height(fraction)

覆盖父级最大约束可用空间的一部分(比例为fraction)

Modifier.width/heightIn(min)

将此值保留为最小宽度/高度,以便使用此维度测量子组件。子组件可以低于此值或高于最大宽度/高度。

Modifier.width/heightIn(max)

这是可以使用的最大宽度/高度。子组件不能使用大于最大宽度/高度的尺寸进行测量。

@Composable
private fun ConstraintsSample1() {
    Text(text = "Fixed Size")
    BoxWithConstraints(modifier = Modifier
        .size(100.dp)
        .border(3.dp, Color.Green)) {
        Box(modifier = Modifier
            .size(50.dp)
            .background(Color.Red))
    }

    Spacer(modifier=Modifier.height(10.dp))
    BoxWithConstraints(modifier = Modifier
        .size(100.dp)
        .border(3.dp, Color.Green)) {
        Box(modifier = Modifier
            .size(150.dp)
            .background(Color.Red))
    }

    Text(text = "widthIn(min)")

    BoxWithConstraints(modifier = Modifier
        .widthIn(min = 100.dp)
        .border(3.dp, Color.Green)) {
        Box(modifier = Modifier
            .size(50.dp)
            .background(Color.Red))
    }

    Spacer(modifier=Modifier.height(10.dp))
    BoxWithConstraints(modifier = Modifier
        .widthIn(min = 100.dp)
        .border(3.dp, Color.Green)) {
        Box(modifier = Modifier
            .size(150.dp)
            .background(Color.Red))
    }


    Text(text = "widthIn(max)")

    BoxWithConstraints(modifier = Modifier
        .widthIn(max = 100.dp)
        .border(3.dp, Color.Green)) {
        Box(modifier = Modifier
            .size(50.dp)
            .background(Color.Red))
    }

    Spacer(modifier=Modifier.height(10.dp))
    BoxWithConstraints(modifier = Modifier
        .widthIn(max = 100.dp)
        .border(3.dp, Color.Green)) {
        Box(modifier = Modifier
            .size(150.dp)
            .background(Color.Red))
    }
}

Modifier.requiredWidth/Height()

当您设置Modifier.size(50.dp).size(100.dp)时,首先应用第一个大小修饰符,但是如果您使用requiredIn

Modifier.size(50.dp).requiredSizeIn(100.dp) 

100.dp被指定,但布局放置在两个尺寸差的一半位置。

@Composable
private fun ConstraintsSample2() {

    Column(modifier = Modifier
        .fillMaxSize()
        .padding(30.dp)
        .border(4.dp, Color.Cyan)) {

        Text(text = "Chaining size modifiers")

        Box(modifier = Modifier
            .size(50.dp)
            .background(Color.Yellow))

        Box(modifier = Modifier
            .size(50.dp)
            .size(100.dp)
            .background(Color.Red))

        Box(modifier = Modifier
            .size(50.dp)
            .requiredSizeIn(100.dp)
            .background(Color.Green))


        Text(text = "widthIn(max)")

        BoxWithConstraints(
            modifier = Modifier
                .width(100.dp)
                .border(3.dp, Color.Green)
        ) {
            Box(
                modifier = Modifier
                    .requiredWidthIn(min = 20.dp, max = 50.dp)
                    .height(50.dp)
                    .background(Color.Red)
            )
        }

        Spacer(modifier = Modifier.height(10.dp))
        BoxWithConstraints(
            modifier = Modifier
                .width(100.dp)
                .border(3.dp, Color.Green)
        ) {
            Box(
                modifier = Modifier
                    .requiredWidthIn(min = 150.dp, max = 200.dp)
                    .height(50.dp)
                    .background(Color.Red)
            )
        }
    }
}

限制条件

限制条件会随着尺寸修改器、垂直/水平滚动或父级选择限制或想要使用最小或最大维度而发生变化。

在我的设备上,最大设备宽度为1080像素,在下面的示例中,200.dp相当于525像素。并且使用了verticalScroll,因此高度是用Constraints.Infinity来测量的。

@Composable
fun ConstraintsSample3() {
    Column(modifier = Modifier) {

        Text(text = "No Dimension Modifier")

        BoxWithConstraints(modifier = Modifier.background(Brown400)) {
            val hasBoundedWidth = constraints.hasBoundedWidth
            val hasFixedWidth = constraints.hasFixedWidth
            val minWidth = constraints.minWidth
            val maxWidth = constraints.maxWidth

            val hasBoundedHeight = constraints.hasBoundedHeight
            val hasFixedHeight = constraints.hasFixedHeight
            val minHeight = constraints.minHeight
            val maxHeight = constraints.maxHeight
            Text(
                "minWidth: $minWidth, maxWidth: $maxWidth\n" +
                        "hasBoundedWidth: $hasBoundedWidth, hasFixedWidth: $hasFixedWidth\n" +
                        "minHeight: $minHeight, maxHeight: $maxHeight\n" +
                        "hasBoundedHeight: $hasBoundedHeight, hasFixedHeight: $hasFixedHeight",
                color = Color.White
            )
        }

        Spacer(modifier = Modifier.height(10.dp))
        Text(text = "FillMaxWidth and 200.dp Height")
        BoxWithConstraints(
            modifier = Modifier
                .fillMaxWidth()
                .height(200.dp)
                .background(Red400)
        ) {
            val hasBoundedWidth = constraints.hasBoundedWidth
            val hasFixedWidth = constraints.hasFixedWidth
            val minWidth = constraints.minWidth
            val maxWidth = constraints.maxWidth

            val hasBoundedHeight = constraints.hasBoundedHeight
            val hasFixedHeight = constraints.hasFixedHeight
            val minHeight = constraints.minHeight
            val maxHeight = constraints.maxHeight
            Text(
                "minWidth: $minWidth, maxWidth: $maxWidth\n" +
                        "hasBoundedWidth: $hasBoundedWidth, hasFixedWidth: $hasFixedWidth\n" +
                        "minHeight: $minHeight, maxHeight: $maxHeight\n" +
                        "hasBoundedHeight: $hasBoundedHeight, hasFixedHeight: $hasFixedHeight",
                color = Color.White
            )
        }

        Spacer(modifier = Modifier.height(10.dp))
        Text(text = "wrapContentSize()")
        BoxWithConstraints(
            modifier = Modifier
                .wrapContentSize()
                .background(Orange400)
        ) {

            val hasBoundedWidth = constraints.hasBoundedWidth
            val hasFixedWidth = constraints.hasFixedWidth
            val minWidth = constraints.minWidth
            val maxWidth = constraints.maxWidth

            val hasBoundedHeight = constraints.hasBoundedHeight
            val hasFixedHeight = constraints.hasFixedHeight
            val minHeight = constraints.minHeight
            val maxHeight = constraints.maxHeight
            Text(
                "minWidth: $minWidth, maxWidth: $maxWidth\n" +
                        "hasBoundedWidth: $hasBoundedWidth\n" +
                        "hasFixedWidth: $hasFixedWidth\n" +
                        "minHeight: $minHeight\n" +
                        "maxHeight: $maxHeight\n" +
                        "hasBoundedHeight: $hasBoundedHeight\n" +
                        "hasFixedHeight: $hasFixedHeight",
                color = Color.White
            )
        }

        Spacer(modifier = Modifier.height(10.dp))
        Text(text = "200.dp Width and Height")
        BoxWithConstraints(
            modifier = Modifier
                .width(200.dp)
                .height(200.dp)
                .background(Green400)
        ) {

            val hasBoundedWidth = constraints.hasBoundedWidth
            val hasFixedWidth = constraints.hasFixedWidth
            val minWidth = constraints.minWidth
            val maxWidth = constraints.maxWidth

            val hasBoundedHeight = constraints.hasBoundedHeight
            val hasFixedHeight = constraints.hasFixedHeight
            val minHeight = constraints.minHeight
            val maxHeight = constraints.maxHeight
            Text(
                "minWidth: $minWidth, maxWidth: $maxWidth\n" +
                        "hasBoundedWidth: $hasBoundedWidth, hasFixedWidth: $hasFixedWidth\n" +
                        "minHeight: $minHeight, maxHeight: $maxHeight\n" +
                        "hasBoundedHeight: $hasBoundedHeight, hasFixedHeight: $hasFixedHeight",
                color = Color.White
            )
        }
    }
}
@Composable
private fun BoxWithConstraintsSample4() {
    Text(text = "200.dp WidthIn(min) and HeightIn(min)")
    BoxWithConstraints(
        modifier = Modifier
            .widthIn(min = 200.dp)
            .heightIn(200.dp)
            .background(Blue400)
    ) {

        val hasBoundedWidth = constraints.hasBoundedWidth
        val hasFixedWidth = constraints.hasFixedWidth
        val minWidth = constraints.minWidth
        val maxWidth = constraints.maxWidth

        val hasBoundedHeight = constraints.hasBoundedHeight
        val hasFixedHeight = constraints.hasFixedHeight
        val minHeight = constraints.minHeight
        val maxHeight = constraints.maxHeight
        Text(
            "minWidth: $minWidth, maxWidth: $maxWidth\n" +
                    "hasBoundedWidth: $hasBoundedWidth, hasFixedWidth: $hasFixedWidth\n" +
                    "minHeight: $minHeight, maxHeight: $maxHeight\n" +
                    "hasBoundedHeight: $hasBoundedHeight, hasFixedHeight: $hasFixedHeight",
            color = Color.White
        )
    }

    Text(text = "200.dp requiredWidth(min) and requiredHeight(min)")
    BoxWithConstraints(
        modifier = Modifier
            .requiredWidthIn(min = 200.dp)
            .requiredHeightIn(200.dp)
            .background(Pink400)
    ) {

        val hasBoundedWidth = constraints.hasBoundedWidth
        val hasFixedWidth = constraints.hasFixedWidth
        val minWidth = constraints.minWidth
        val maxWidth = constraints.maxWidth

        val hasBoundedHeight = constraints.hasBoundedHeight
        val hasFixedHeight = constraints.hasFixedHeight
        val minHeight = constraints.minHeight
        val maxHeight = constraints.maxHeight
        Text(
            "minWidth: $minWidth, maxWidth: $maxWidth\n" +
                    "hasBoundedWidth: $hasBoundedWidth, hasFixedWidth: $hasFixedWidth\n" +
                    "minHeight: $minHeight, maxHeight: $maxHeight\n" +
                    "hasBoundedHeight: $hasBoundedHeight, hasFixedHeight: $hasFixedHeight",
            color = Color.White
        )
    }

    Text(text = "200.dp defaultMinSize()")
    BoxWithConstraints(
        modifier = Modifier
            .defaultMinSize(200.dp)
            .background(Pink400)
    ) {

        val hasBoundedWidth = constraints.hasBoundedWidth
        val hasFixedWidth = constraints.hasFixedWidth
        val minWidth = constraints.minWidth
        val maxWidth = constraints.maxWidth

        val hasBoundedHeight = constraints.hasBoundedHeight
        val hasFixedHeight = constraints.hasFixedHeight
        val minHeight = constraints.minHeight
        val maxHeight = constraints.maxHeight
        Text(
            "minWidth: $minWidth, maxWidth: $maxWidth\n" +
                    "hasBoundedWidth: $hasBoundedWidth, hasFixedWidth: $hasFixedWidth\n" +
                    "minHeight: $minHeight, maxHeight: $maxHeight\n" +
                    "hasBoundedHeight: $hasBoundedHeight, hasFixedHeight: $hasFixedHeight",
            color = Color.White
        )
    }

    Text(text = "200.dp WidthIn(max)")
    BoxWithConstraints(
        modifier = Modifier
            .widthIn(max = 200.dp)
            .background(Purple400)
    ) {

        val hasBoundedWidth = constraints.hasBoundedWidth
        val hasFixedWidth = constraints.hasFixedWidth
        val minWidth = constraints.minWidth
        val maxWidth = constraints.maxWidth

        val hasBoundedHeight = constraints.hasBoundedHeight
        val hasFixedHeight = constraints.hasFixedHeight
        val minHeight = constraints.minHeight
        val maxHeight = constraints.maxHeight
        Text(
            "minWidth: $minWidth, maxWidth: $maxWidth\n" +
                    "hasBoundedWidth: $hasBoundedWidth, hasFixedWidth: $hasFixedWidth\n" +
                    "minHeight: $minHeight, maxHeight: $maxHeight\n" +
                    "hasBoundedHeight: $hasBoundedHeight, hasFixedHeight: $hasFixedHeight",
            color = Color.White
        )
    }
}

我非常感激。 - Kotlin Learner
那么,如果我想制作上面的屏幕截图,我需要使用requireWidth和高度吗? - Kotlin Learner
如果您不希望在字符串更改时更改TextFieldSize,请使用Modifier.width(56.dp)。如果您希望它具有最小宽度为56.dp并且随着字符串的增长而增长,请使用Modifier.widthIn(min = 56.dp)或Modifier.requiredWidthIn(min = 56.dp)。但是,使用requiredWidthIn时要注意不要将父级宽度设置为小于56.dp。 - Thracian
更新的答案。尝试 TextFields 以便自行查看。如果父级宽度较小,则最后一个 TextField 中的 requiredWidthIn 将导致 TextField 溢出到左侧,这是你应该注意的。required 的目的是强制使用你的 Modifier(但如果存在另一个 Modifier,则应在父级范围内),以避免将你的 composable 弄出父级或跳出父级。 - Thracian
我认为我需要提出另一个问题,因为我的文本字段在56dp下不够清晰可见。我需要自定义这段文本。 - Kotlin Learner

2

对于您的用例,应使用requiredWidth()

1. fillMaxWidth

用于填充可用宽度。
它接受分数作为参数,并在未提供时默认为1.0F

2. widthIn

使用widthIn提供大小范围。
它以最小宽度和最大宽度为参数。

3. requiredWidth

使用requiredWidth强制指定宽度。
(这是针对您的用例)

4. width

使用width指定首选宽度。如果没有覆盖给定首选项的约束,则使用给定的首选宽度。

示例代码

@Composable
fun WidthTypes() {
    Column(
        modifier = Modifier.fillMaxSize(),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.SpaceEvenly,
    ) {
        Box(
            modifier = Modifier
                .background(Red)
                .height(40.dp)
                .fillMaxWidth(0.9F),
        ) {
            Box(
                modifier = Modifier
                    .background(Blue)
                    .height(10.dp)
                    .width(80.dp),
            )
        }
        Box(
            modifier = Modifier
                .background(Red)
                .height(40.dp)
                .widthIn(40.dp, 100.dp),
        ) {
            Box(
                modifier = Modifier
                    .background(Blue)
                    .height(10.dp)
                    .width(80.dp),
            )
        }
        Box(
            modifier = Modifier
                .background(Red)
                .height(40.dp)
                .requiredWidth(40.dp),
        ) {
            Box(
                modifier = Modifier
                    .background(Blue)
                    .height(10.dp)
                    .width(80.dp),
            )
        }
        Box(
            modifier = Modifier
                .background(Red)
                .height(40.dp)
                .widthIn(70.dp, 100.dp)
                .width(40.dp),
        ) {
            Box(
                modifier = Modifier
                    .background(Blue)
                    .height(10.dp)
                    .width(80.dp),
            )
        }
    }
}

请注意,第四个红色框的宽度为70.dp,即使指定了width40.dp。这是因为使用了widthIn,它覆盖了宽度值。
当我们使用requiredWidth时,这种情况不会发生。

0

我不确定我是否理解了你的问题

如果你是在寻求帮助,想要制作一个类似参考图像的文本框:第一种情况是固定宽度,你还想使用 .height 来进行高度调整。

在第二种情况下:当你给出最小值时,允许尺寸超过 56.dp。但这对你的情况不是一个选项,因为你需要一个固定的尺寸。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接