Question

How do I make a Text composable take up x% of the Row's width when there's a IconButton in the row?

I have a Row that has an icon button on the left, then 16dp padding, then a Text that takes up the remaining width in the Row, and finally on the right, another Text that should take up 25% of the width of the Row. Everything works except that the second Text is actually taking up 25% of the width of the Row, excluding the width of the icon button. This makes the second Text's width too thin.

I need the second Text to be exactly 25% of the entire Row's width because I have other Rows with Texts (not shown) that need to be aligned with this one.

So how do I make the IconButton's width actually be factored into the width of the second Text? Here's the simplified snippet:

Row(
    modifier = Modifier
        .padding(bottom = 16.dp)
        .fillMaxWidth()
        .background( color = Color(50, 50, 50) )
) {
    IconButton(
        modifier = Modifier
            .background(Color(100, 100, 100), CircleShape),
        onClick = { /* nothing */ }
    ) {
        Icon(Icons.Filled.Star,null, tint = Color(255, 192,0))
    }

    Text(
        modifier = Modifier
            .weight(1f) // Use weight 1f to take up remaining space
            .padding(start = 16.dp) // put left padding on the text: between the icon button & the text
            .background(color = Color(100, 100, 100)),
        text = "Remaining space",
        style = MaterialTheme.typography.bodyMedium
    )

    Text(
        text = "25%",
        modifier = Modifier
            .fillMaxWidth(0.25f) // Take up exactly 25% of the width
            .background(color = Color(150, 150, 150)),
        textAlign = TextAlign.Center,
        style = MaterialTheme.typography.bodyMedium
    )
}

Here's a (cropped) screenshot of the output: enter image description here

And a screenshot that proves that the second Text only takes up 25% of the Row's width excluding the IconButton's width (it looks like the second Text's width * 4 overlaps the IconButton by a couple of pixels, but in my code before I simplified it, there was no overlap so I don't think it's relevant):enter image description here

Initially, the icon button was in its own function, so I extracted it from the function. I've also tried setting the modifier.size() of the icon button instead of just using the default size. Both of these had no effect.

Expected result: the second Text takes up exactly 25% of the width of the icon button + padding + first Text + second Text.

Actual result: the second Text takes up exactly 25% of only the width of the padding + first Text + second Text.

 5  60  5
1 Jan 1970

Solution

 2

You could wrap the IconButton and the first Text in an additional Row where you explicitly set the width to 75%:

Row(
    modifier = Modifier.fillMaxWidth(0.75f),
) {
    IconButton()

    Text(
        modifier = Modifier.weight(1f) // Use weight 1f to take up the remaining space
    )
}

Text(
    modifier = Modifier.fillMaxWidth() // Take up the remaining 25% of the parent's width
)

Then the second Text can take up the remaining 25%:

2024-07-07
Leviathan