This is a pretty interesting question. IntrinsicSizes come from recursively from children Composable that are set before composing children, sort of placeholder.
You need to subcompose again, measure your child Composable with smaller height with max height for them to have equal heights.
I created 2 samples using same SubcomposeLayout i built.
@Composable
private fun ImageSubcomposeRow(modifier: Modifier, content: @Composable () -> Unit) {
SubcomposeLayout(modifier = modifier) { constraints: Constraints ->
var subcomposeIndex = 0
var placeables: List<Placeable> = subcompose(subcomposeIndex++, content)
.map {
it.measure(constraints)
}
if (placeables.size == 2) {
val heightLeft = placeables.first().measuredHeight
val heightRight = placeables.last().measuredHeight
println(
"🚀 SubcomposeRow Left height: $heightLeft\n" +
"RIGHT height: $heightRight"
)
// Get maximum height
val maxHeight = heightLeft.coerceAtMost(heightRight)
val maxWidth = (heightLeft + heightRight).coerceAtMost(constraints.maxWidth)
// Remeasure every element using height of tallest item using it as min height
// and max width should be the half of the max width of ancestor to display both with same width
// images
placeables = subcompose(subcomposeIndex, content).map { measurable: Measurable ->
measurable.measure(
constraints.copy(
minHeight = maxHeight,
minWidth = 0,
maxWidth = constraints.maxWidth / 2
)
)
}
// We place our Composables side by side using first ones width for second ones
// position
var x = 0
layout(maxWidth, maxHeight) {
placeables.forEach { placeable: Placeable ->
placeable.placeRelative(x, 0)
x += placeable.width
}
}
} else {
layout(0, 0) {}
}
}
}
Example1
Create a mutableStateList, which can trigger recomposition when we add new items to it, and i put both painters on success then call SubcomposeLayout. This will display images when both are loaded
@Composable
private fun ImageExample() {
Column {
val blocks = listOf(
"https://64.media.tumblr.com/5c1b241725c877cfd7c2a83910530ad0/efd70ac460498fb4-da/s1280x1920/c70cfdf1403aac31a55ebff90604f381081d8557.jpg",
"https://64.media.tumblr.com/8da6ed3327f22f582a94131b8fca816a/efd70ac460498fb4-83/s2048x3072/c6aa09d50fa9ddb4ec67d2c779c7f3a425a551c3.jpg"
)
val imageList = remember {
mutableStateListOf<Painter>()
}
blocks.forEach { itemIndex ->
println("Item: $itemIndex")
rememberAsyncImagePainter(
model = ImageRequest.Builder(LocalContext.current)
.data(itemIndex)
.size(coil.size.Size.ORIGINAL)
.build(),
contentScale = ContentScale.FillWidth,
onSuccess = { state ->
imageList.add(state.painter)
}
)
}
if (imageList.size == 2) {
ImageSubcomposeRow(
modifier = Modifier
.fillMaxWidth()
.aspectRatio(4 / 3f)
.border(3.dp, Color.Yellow)
) {
imageList.forEach { painter ->
Image(
modifier = Modifier
.fillMaxWidth()
.border(2.dp, Color.Cyan),
painter = painter,
contentScale = ContentScale.FillHeight,
contentDescription = null,
)
}
}
}
}
}
Second example is as in question
@Composable
private fun ImageExample2() {
Column {
val blocks = listOf(
"https://64.media.tumblr.com/5c1b241725c877cfd7c2a83910530ad0/efd70ac460498fb4-da/s1280x1920/c70cfdf1403aac31a55ebff90604f381081d8557.jpg",
"https://64.media.tumblr.com/8da6ed3327f22f582a94131b8fca816a/efd70ac460498fb4-83/s2048x3072/c6aa09d50fa9ddb4ec67d2c779c7f3a425a551c3.jpg"
)
ImageSubcomposeRow(
modifier = Modifier
.fillMaxWidth()
.aspectRatio(4 / 3f)
.border(3.dp, Color.Yellow)
) {
blocks.forEach { itemIndex ->
val painter = rememberAsyncImagePainter(
model = ImageRequest.Builder(LocalContext.current)
.data(itemIndex)
.size(coil.size.Size.ORIGINAL)
.build(),
contentScale = ContentScale.FillWidth,
)
Image(
modifier = Modifier
.fillMaxWidth()
.border(2.dp, Color.Cyan),
painter = painter,
contentScale = ContentScale.FillHeight,
contentDescription = null,
)
}
}
}
}
Test
Column(modifier = Modifier.fillMaxSize()) {
Text(text = "Example1")
ImageExample()
Text(text = "Example2")
ImageExample2()
}
Also, as third option, this question probably can be solved using calculating heights based on height ratios of painters after getting both as in first example then set height for both Image without SubcomposeLayout.
SubcomposeLayout is needed when you don't know dimensions of Composables in advance before you measure or one depends on others dimensions. With subcompose
you measure again with required constraints to have Composables with required dimensions.
Result