Jetpack Compose - 将图像缩放到 Column/Row 中的可用大小

Jetpack Compose - Make Image scale to the available size in Column/Row

考虑下图:

我有一个 Column 有一个 Image 和另一个 Column 有一些 Text 元素。我想要做的是让 Image 统一缩放到可用的 space。我就是做不到。

Column(
    modifier = Modifier
        .fillMaxSize()
        .background(Color.Cyan)
        .padding(horizontal = 16.dp),
    verticalArrangement = Arrangement.SpaceEvenly
) {
    Image(
        modifier = Modifier.fillMaxWidth(),
        painter = painterResource(R.drawable.rocket_boy),
        contentDescription = null,
        contentScale = ContentScale.Fit
    )
    Column(
        modifier = Modifier.fillMaxWidth(),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        repeat(20) {
            Text(text = "${it}")
        }
    }
}

我尝试的其中一件事是将 Image 的大小设置为 fillMaxSize 并将第二个 Columnweight 的大小设置为 1f ,但它什么也没做。也许我需要固定第二个 Column 的大小?非常感谢任何帮助。

您的图像尺寸似乎小于屏幕最大宽度,因此图像的容器填充宽度,但图像仍然很小,如​​果您填充图像的高度,它会正确缩放,但图像容器填充列表下方的所有 space。您可以尝试为修饰符设置纵横比,以防止容器填充所有可用 space:

...
val painter = painterResource(id = R.drawable.ic_dismiss_24)
Image(
  modifier = Modifier
                .aspectRatio(ratio = painter.intrinsicSize.height / 
  painter.intrinsicSize.width)
                .fillMaxWidth()
                .fillMaxHeight(),
  painter = painter,
  contentDescription = null,
  contentScale = ContentScale.Fit
)
...

您没有在正确的 child 上使用 Modifier.weight。它应该应用于视图,您需要填充 parent.

的其余部分

The parent will divide the vertical space remaining after measuring unweighted child elements and distribute it according to this weight.

Modifier.weight 有参数 fill,默认参数为 true。此默认参数与 Modifier.fillMaxHeight() 相同(在 Column 的情况下),如果您不需要填充所有可用高度,您可以指定 false:

Column(
    modifier = Modifier
        .fillMaxSize()
        .background(Color.Cyan)
        .padding(horizontal = 16.dp),
    verticalArrangement = Arrangement.SpaceEvenly,
    horizontalAlignment = Alignment.CenterHorizontally,
) {
    val painter = painterResource(R.drawable.ic_redo)
    Image(
        modifier = Modifier.weight(1f, fill = false)
            .aspectRatio(painter.intrinsicSize.width / painter.intrinsicSize.height)
            .fillMaxWidth(),
        painter = painter,
        contentDescription = null,
        contentScale = ContentScale.Fit
    )
    Column(
        horizontalAlignment = Alignment.CenterHorizontally,
        modifier = Modifier.fillMaxWidth()
    ) {
        repeat(20) {
            Text(text = "${it}")
        }
    }
}

使用 Column 无法正常工作,但我使用 ConstraintLayout 成功了,在 Nestor 的帮助下 aspectRatio

ConstraintLayout(
    modifier = Modifier.fillMaxSize()
) {
    val (button, text) = createRefs()

    val painter = painterResource(R.drawable.rocket_boy)
    Image(
        modifier = Modifier
            .aspectRatio(ratio = painter.intrinsicSize.width /
                    painter.intrinsicSize.height)
            .padding(16.dp)
            .constrainAs(text) {
                top.linkTo(parent.top)
                bottom.linkTo(button.top)
                height = Dimension.preferredWrapContent
                width = Dimension.preferredWrapContent
                start.linkTo(parent.start)
                end.linkTo(parent.end)
            },
        painter = painter,
        contentDescription = null,
        contentScale = ContentScale.Fit
    )

    Column(Modifier.constrainAs(button) {
        bottom.linkTo(parent.bottom, margin = 16.dp)
        top.linkTo(text.bottom)
        start.linkTo(parent.start)
        end.linkTo(parent.end)
        height = Dimension.wrapContent
    }) {
        repeat(5) {
            Text(text = "$it")
        }
    }
}

但如果有人认为用 Column 代替 ConstraintLayout 仍然可以完成,他可以 post 回答,我可以接受。

如果我们考虑父级 Column 的高度 - 作为 Image 和嵌套 Column 高度的总和 - 可以说你的高度Image 应该等于高度的余数,减去父级 Column 的高度 - 嵌套的 Column.

的高度
var textInColumnSize by remember { mutableStateOf(Size.Zero) }
var globalColumnSize by remember { mutableStateOf(Size.Zero) }
val imageHeight: Dp =
    LocalDensity.current.run { (globalColumnSize.height - 
    textInColumnSize.height).toDp() }

Column(
    modifier = Modifier
        .fillMaxSize()
        .onGloballyPositioned { coordinates ->
            globalColumnSize = coordinates.size.toSize()
        }
        .background(Color.Cyan)
        .padding(horizontal = 16.dp),
    horizontalAlignment = Alignment.CenterHorizontally,
    verticalArrangement = Arrangement.SpaceEvenly
) {

    Image(
        modifier = Modifier
            .fillMaxWidth()
            .height(imageHeight),
        painter = painterResource(R.drawable.rocket_boy),
        contentDescription = null,
    )
    Column(
        modifier = Modifier
            .fillMaxWidth()
            .onGloballyPositioned { coordinates ->
                textInColumnSize = coordinates.size.toSize()
            },
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        repeat(10) {
            Text(text = "$it")
        }
    }
}