If aligning Image and Text with static text end of your Composable is okay you can set Modifier.weight(1f) for Text with dynamic text so it will cover the space that is not used by Image and Text with static text.
Column(modifier = Modifier.fillMaxSize()) {
Row(
modifier = Modifier
.fillMaxWidth()
.height(100.dp)
) {
Text("Dynamic text", modifier = Modifier.weight(1f))
Image(
modifier = Modifier.size(50.dp),
painter = painterResource(id = R.drawable.landscape1),
contentDescription = ""
)
Text("text")
}
Row(
modifier = Modifier
.fillMaxWidth()
.height(100.dp)
) {
Text("Dynamic longer text", modifier = Modifier.weight(1f))
Image(
modifier = Modifier.size(50.dp),
painter = painterResource(id = R.drawable.landscape1),
contentDescription = ""
)
Text("text")
}
}
If you want a layout like in first table you should use a Layout. If you don't have any experience with Layout it might be complicated.
Steps to accomplish what's needed
1- First measure your every child Composable with Constraints and get placeable
val placeables: List<Placeable> = measurables.map { measurable ->
measurable.measure(constraints)
}
2- Get maximum width of dynamic texts, this will be our threshold for each row's second element x position, i added a padding but you can add padding to Text if you want to
// Get the maximum with of first Text on each Row
val maxDynamicWidth = placeables.filterIndexed { index, _ ->
index % 3 == 0
}.maxOf { it.width } + padding
3- Get height of each row. We will use row height for placing every 3 Composables
val rowHeights = mutableListOf<Int>()
var maxHeight = 0
// Get height for each row
placeables.forEachIndexed { index, placeable ->
maxHeight = if (index % 3 == 2) {
rowHeights.add(maxHeight)
0
} else {
placeable.height.coerceAtLeast(maxHeight)
}
}
4- get total height of our Layout, you can use constraints.maxHeight if you want to and then layout every 3 Composables on each row
val totalHeight = rowHeights.sum()
var y = 0
var x = 0
layout(constraints.maxWidth, totalHeight) {
placeables.forEachIndexed { index, placeable ->
if (index % 3 == 0) {
if (index > 0) y += rowHeights[index / 3]
placeable.placeRelative(0, y)
x = maxDynamicWidth
} else {
placeable.placeRelative(x, y)
x += placeable.width
}
}
}
Full implementation
@Composable
private fun MyLayout(
modifier: Modifier = Modifier,
paddingAfterDynamicText: Dp = 0.dp,
content: @Composable () -> Unit
) {
val padding = with(LocalDensity.current) {
paddingAfterDynamicText.roundToPx()
}
Layout(
modifier = modifier,
content = content
) { measurables: List<Measurable>, constraints: Constraints ->
require(measurables.size % 3 == 0)
val placeables: List<Placeable> = measurables.map { measurable ->
measurable.measure(constraints)
}
// Get the maximum with of first Text on each Row
val maxDynamicWidth = placeables.filterIndexed { index, _ ->
index % 3 == 0
}.maxOf { it.width } + padding
val rowHeights = mutableListOf<Int>()
var maxHeight = 0
// Get height for each row
placeables.forEachIndexed { index, placeable ->
maxHeight = if (index % 3 == 2) {
rowHeights.add(maxHeight)
0
} else {
placeable.height.coerceAtLeast(maxHeight)
}
}
val totalHeight = rowHeights.sum()
var y = 0
var x = 0
// i put Composable on each row to top of the Row
// (y-placeable.height)/2 places them to center of row
layout(constraints.maxWidth, totalHeight) {
placeables.forEachIndexed { index, placeable ->
if (index % 3 == 0) {
if (index > 0) y += rowHeights[index / 3]
placeable.placeRelative(0, y)
x = maxDynamicWidth
} else {
placeable.placeRelative(x, y)
x += placeable.width
}
}
}
}
}
You can use it as
MyLayout(
modifier = Modifier.border(3.dp, Color.Red),
paddingAfterDynamicText = 15.dp
) {
Text("Dynamic text")
Image(
modifier = Modifier.size(50.dp),
painter = painterResource(id = R.drawable.landscape1),
contentDescription = ""
)
Text("text")
Text("Dynamic longer text")
Image(
modifier = Modifier.size(50.dp),
painter = painterResource(id = R.drawable.landscape1),
contentDescription = ""
)
Text("text")
}
Result
