Jetpack Compose中的权重

65
能否在Jetpack Compose中设置权重?例如,我想以这样的方式设置它:一个项目的权重为布局的1/3,另一个项目占用剩余的2/3。
在XML / ViewGroup风格中,您可以使用LinearLayout和ConstraintLayout实现此目的。但是,令人失望的是,使用Jetpack Compose似乎不可能。 示例: 在ConstraintLayout中,可以按以下方式完成这个问题:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <View
        android:layout_width="0dp"
        android:layout_height="100dp"
        android:id="@+id/red"
        android:background="@color/red"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/blue"
        app:layout_constraintHorizontal_weight="1"/>
    <View
        android:layout_width="0dp"
        android:layout_height="100dp"
        android:id="@+id/blue"
        android:background="@color/blue"
        app:layout_constraintStart_toEndOf="@id/red"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_weight="2"/>
</androidx.constraintlayout.widget.ConstraintLayout>

在LinearLayout中,可以通过以下方式来实现:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal">
    <View
        android:layout_width="0dp"
        android:layout_height="100dp"
        android:id="@+id/red"
        android:background="@color/red"
        android:layout_weight="1"/>
    <View
        android:layout_width="0dp"
        android:layout_height="100dp"
        android:id="@+id/blue"
        android:background="@color/blue"
        android:layout_weight="2"/>
</LinearLayout>

我知道您可以使用表格来获取均匀分布的内容,但我想要一个不均匀的分布。


2
在你在这里提出问题后,如果你得到了一个可接受的答案,你应该通过点击其旁边的勾选标记“接受”该答案。这将为你和回答你问题的人都加分。你可以在这里了解更多关于接受答案的信息:如何接受答案?为什么我们要接受答案?如果有人回答了我的问题,我该怎么办? - MarianD
7个回答

133

您可以使用 Modifier.weight
例如:

Row() {
    Column(
        Modifier.weight(1f).background(Blue)
    ){
        Text(text = "Weight = 1", color = Color.White)
    }
    Column(
        Modifier.weight(2f).background(Yellow)
    ) {
        Text(text = "Weight = 2")
    }
}

在此输入图片描述


对于像我这样真正想要避免嵌套布局的狂热分子,Compose 不会受到影响! - ZooMagic
@desgraci 你可以使用 weight(0f) 或者直接省略 weight 修饰符。 - Gabriele Mariotti

13

自从"0.1.0-dev09"版本,修饰符被移到了接口上,您可以使用

Modifier.weight(float, boolean)

来将未加权子元素的测量后剩余的垂直/水平空间分割,并根据此权重进行分配。

 Column {
        Row(modifier = Modifier.weight(2.0f, true)) {
            Box (
                modifier = Modifier.fillMaxWidth().fillMaxHeight(),
                backgroundColor = Color.Red
            )
        }
        Row(modifier = Modifier.weight(1.0f, true)) {
            Box (
                modifier = Modifier.fillMaxWidth().fillMaxHeight(),
                backgroundColor = Color.Blue,
                gravity = ContentGravity.Center
            ) {
                Text(text = "A sample text")
            }
        }
        Row(modifier = Modifier.weight(2.0f, true)) {
            Box (
                modifier = Modifier.fillMaxWidth().fillMaxHeight(),
                backgroundColor = Color.Yellow
            )
        }
    }

默认值为true,所以您不需要指定它。 - MSpeed
我如何知道我的视图应该有多高的权重?假设我有一个包含三个对象的列。第二个对象占据了大部分布局,以至于第一个和最后一个对象具有默认高度,而第二个对象应填充第一个和最后一个对象之间的空间。在XML中,您可以将这些对象放入LinearLayout中,并将第二个视图的权重设置为1。在Jetpack Compose中,我该如何实现这一点?谢谢 - Mark Delphi

2
“Jetpack Compose”的“0.1.0-dev04”版本包含变更,FlexRow已被弃用。我可以提出以下解决方案:
Row {
    Card(modifier = LayoutFlexible(1f), color = Color.Red) {
        Container(expanded = true, height = 50.dp) {

        }
    }
    Card(modifier = LayoutFlexible(2f), color = Color.Green) {
        Container(expanded = true, height = 50.dp) {

        }
    }
}

结果: enter image description here LayoutFlexible(flex = _f)可以帮助我们解决问题,Modifier可以应用于任何容器。

1

这里是我项目中使用权重的示例

可组合项

@Composable
fun PokemonAttributes(
    pokemonWeight: Int,
    pokemonHeight: Int,
    sectionHeight: Dp = 80.dp
) {
    val weight = remember { weightHeightMeasurement(pokemonWeight) }
    val height = remember { weightHeightMeasurement(pokemonHeight) }

    Row(
        modifier = Modifier.fillMaxWidth()
    ) {
        PokemonDetailDataItem(
            dataValue = weight,
            dataTag = stringResource(id = R.string.str_weight),
            dataUnit = stringResource(id = R.string.str_kg),
            dataIcon = painterResource(id = R.drawable.ic_pokemon_weight),
            modifier = Modifier.weight(1f)
        )
        Spacer(modifier = Modifier
            .size(1.dp, sectionHeight)
            .background(Color.LightGray))
        PokemonDetailDataItem(
            dataValue = height,
            dataTag = stringResource(id = R.string.str_height),
            dataUnit = stringResource(id = R.string.str_meter),
            dataIcon = painterResource(id = R.drawable.ic_pokemon_height),
            modifier = Modifier.weight(1f)
        )
    }
}

@Composable
fun PokemonDetailDataItem(
    dataValue: String,
    dataTag: String,
    dataUnit: String,
    dataIcon: Painter,
    modifier: Modifier = Modifier
) {

    val iconSize : Dp = 50.dp
    val attributeSpacing : Dp = 8.dp
    val attributeValueSize = 18.sp
    val attributeTagSize = 12.sp
    val displayText = "$dataValue $dataUnit"

    Row(
        verticalAlignment = Alignment.CenterVertically,
        horizontalArrangement = Arrangement.Center,
        modifier = modifier
    ) {
        Icon(
            painter = dataIcon,
            contentDescription = null,
            modifier = Modifier.size(iconSize),
            tint = MaterialTheme.colors.onSurface
        )
        Spacer(modifier = Modifier.width(10.dp))
        Column(
            horizontalAlignment = Alignment.CenterHorizontally,
            verticalArrangement = Arrangement.Center
        ) {
            Text(
                text = displayText,
                fontFamily = Nunito,
                fontWeight = FontWeight.Bold,
                fontSize = attributeValueSize,
                color = MaterialTheme.colors.onSurface
            )
            Text(
                text = dataTag,
                fontFamily = Nunito,
                fontWeight = FontWeight.Normal,
                fontSize = attributeTagSize,
                color = Color.LightGray
            )
        }

    }
}

输出

enter image description here


1

在容器内使用Modifier.weight(float)对对象进行调整。 你也可以使用constraintlayout或低级别的Layout Composable。查看Compose Pathways中的官方Compose布局codelab,了解更多信息。


-1
Row() {
    OutlinedTextField(
        modifier = modifier.weight(1f).clickable {

        },
        value = formatDate(date) ?: "",
        onValueChange = {  },
        label = { Text("Date") },
        singleLine = true,
        readOnly = true
    )

    Spacer(modifier = Modifier.padding(4.dp))

    OutlinedTextField(
        modifier = modifier.weight(1f),
        value = formatTime(date) ?: "",
        onValueChange = {  },
        label = { Text("Time") },
        singleLine = true
    )
}

-2

Compose 将状态转化为 UI 元素。

元素的组合 元素的布局 元素的绘制

标准布局组件

@Composable
fun ArtistCard() {
    Column {
        Text("Alfred Sisley")
        Text("3 minutes ago")
    }
}

同样地,使用行来在屏幕上水平放置元素。列和行都支持配置它们包含的元素的对齐方式。

  @Composable
    fun ArtistCard(artist: Artist) {
        Row(verticalAlignment = Alignment.CenterVertically) {
            Image(/*...*/)
            Column {
                Text(artist.name)
                Text(artist.lastSeenOnline)
            }
        }
    }

使用Box将元素放在另一个元素的上方。Box还支持配置其包含元素的特定对齐方式。
@Composable
fun ArtistAvatar(artist: Artist) {
    Box {
        Image(/*...*/)
        Icon(/*...*/)
    }
}

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