I have a "simple" layout in Compose, where in a Column
there are two elements:
- top image
- a grid of 4 squares underneath, each square containing some text
I'd like the layout to have the following behaviour:
- set the maximum height of the image to be
screenWidth
- set the minimum height of the image to be
200.dp
- the image should always be in a square container (cropping of the image is fine)
- let the grid "grow" as much as it needs to, to wrap around the content, making the image shrink as necessary
This means that if the text in the squares is short, the image will cover a large square on the top. But if any of the square text is really, long, I want the whole grid to scale up and shrink the image. These are the desirable outcomes:
- When text is short enough
- When a piece of text is really long
I have tried this with ConstraintLayout
in Compose, but I can't get the squares to scale properly.
With a Column
, I can't get the options to grow with large content - the text just gets truncated and the image remains a massive square.
These are the components I'd built:
// the screen
Column {
Box(modifier = Modifier
.heightIn(min = 200.dp, max = screenWidth)
.aspectRatio(1f)
.border(BorderStroke(1.dp, Color.Green))
.align(Alignment.CenterHorizontally),
) {
Image(
painter = painterResource(id = R.drawable.puppy),
contentDescription = null,
contentScale = ContentScale.Crop
)
}
OptionsGrid(choicesList, modifier = Modifier.heightIn(max = screenHeight - 200.dp))
}
@Composable
fun OptionsGrid(choicesList: List<List<String>>, modifier: Modifier = Modifier) {
Column(
modifier = modifier
.border(1.dp, Color.Blue)
.padding(top = 4.dp, bottom = 4.dp)
.fillMaxHeight(),
verticalArrangement = Arrangement.Center
) {
choicesList.forEach { choicesPair ->
Row(modifier = Modifier.weight(0.5f)) {
choicesPair.forEach { choice ->
Box(
modifier = Modifier
.padding(4.dp)
.background(Color.White)
.weight(0.5f)
) {
Option(choice = choice)
}
}
}
}
}
}
@Composable
fun Option(choice: String) {
Box(
modifier = Modifier
.fillMaxSize()
.background(Color.Yellow)
.border(BorderStroke(1.dp, Color.Red)),
contentAlignment = Alignment.Center
) {
Text(
text = choice,
modifier = Modifier.padding(8.dp),
textAlign = TextAlign.Center,
)
}
}
Do I need a custom layout for this? I suppose what's happening here is that the Column
is measuring the image first, letting it be its maximum height, because there is space for that on the screen, and then when measuring the grid, it gives it the remaining space and nothing more.
So I'd need a layout which starts measuring from the bottom?