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

2

6

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)
        )
    }
}
Bombsight answered 23/8, 2022 at 6:57 Comment(0)
D
5

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

Deviate answered 23/8, 2022 at 7:44 Comment(1)
Thank you, didn't know about .width(IntrinsicSize.Max) before this, that is the key ingredient! Without it, wrapContent will not work properly and the button will fill the max width when we set .weight(1f).Parmenides
N
2

I believe you need to set an intrinsic width on your Button. Something like

Button(
        onClick = { /* */ },
        modifier = modifier.width(IntrinsicSize.Min)
    )

See the documentation here, https://developer.android.com/jetpack/compose/layouts/intrinsic-measurements

Nsf answered 23/8, 2022 at 7:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.