Search code examples
androidandroid-layoutandroid-jetpack-composeandroid-compose-buttonandroid-jetpack-compose-button

How to use weight in a Button to align Text on the left and Icon on the right


I'm building a re-usable Button component in Jetpack Compose, which is basically a Row. The button should have a text on the left end and an icon on the right end. This works straight forward like this:

@Composable
fun MyButton(
    text: String,
    modifier: Modifier = Modifier
) {
    Button(
        onClick = { /* */ },
        modifier = modifier
    ) { // RowScope
        Text(
            text = text
        )
        Spacer(modifier = Modifier.width(8.dp))
        Icon(
            painter = painterResource(
                id = android.R.drawable.ic_dialog_info
            ),
            contentDescription = null
        )
    }
}

However, if the button gets applied a fixed width, the text & icon is centered and not at the left/right end.

enter image description here

So I tried adding modifier = Modifier.weight(1F) to the Text so it fills up any additional space. But this causes a button without a fixed width to take up as much space as it can.

enter image description here

How can I build a Compose component that works in both cases: When a width is defined and when it is wrap-to-content?

My screen layout:

@Composable
fun MyScreen() {
    Column(
        horizontalAlignment = Alignment.CenterHorizontally,
        modifier = Modifier.fillMaxSize()
    ) {
        Spacer(modifier = Modifier.height(8.dp))
        MyButton(
            text = "variable width",
            modifier = Modifier.wrapContentWidth()
        )
        Spacer(modifier = Modifier.height(8.dp))
        MyButton(
            text = "fixed width",
            modifier = Modifier.width(300.dp)
        )
    }
}

Solution

  • The content of a Button is a RowScope.Just apply a weight(1f) modifier to the Text together with TextOverflow.Ellipsis.

    Something like:

    Button(
        onClick = { /* */ },
        modifier = modifier.width(IntrinsicSize.Max)
    ) { // RowScope
        Text(
            text = text,
            maxLines = 1,
            modifier = Modifier.weight(1f),
            overflow = TextOverflow.Ellipsis
        )
        Spacer(modifier = Modifier.width(8.dp))
        Icon(
            painter = painterResource(
                id = android.R.drawable.ic_dialog_info
            ),
            contentDescription = null
        )
    }
    

    enter image description here