JetPack Compose Button with drawable

18.7k views Asked by At

How can we achieve this in jetpack compose

enter image description here

I'm doing something like this

Button(
    elevation = ButtonDefaults.elevation(
        defaultElevation = 0.dp,
        pressedElevation = 8.dp,
        disabledElevation = 0.dp
    ),
    onClick = { onClick },
    shape = RoundedCornerShape(28.dp),
    modifier = modifier
        .fillMaxWidth()
        .shadow(0.dp),
    contentPadding = PaddingValues(15.dp),
    colors = ButtonDefaults.buttonColors(backgroundColor = Color.White),
    border = BorderStroke(1.dp, Color.Grey)
) {
    Box(modifier = modifier.fillMaxWidth(),
        contentAlignment = Alignment.Center) {
        Icon(
            imageVector = imageVector,
            modifier = Modifier
                .size(18.dp),
            contentDescription = "drawable icons",
            tint = Color.Unspecified
        )
        Spacer(modifier = Modifier.width(10.dp))
        Text(
            text = buttonText,
            color = Color.Black,
            textAlign = TextAlign.Center
        )
    }
}

enter image description here

So as you can see the Google logo is just left of the text I need it at the start of the box so how can I do this.

6

There are 6 answers

1
Dheeraj Gupta On BEST ANSWER
@Composable
fun GoogleButton(
    modifier: Modifier = Modifier,
    imageVector: ImageVector,
    buttonText: String,
    onClick: (isEnabled: Boolean) -> Unit = {},
    enable: Boolean = true,
    backgroundColor: Color,
    fontColor: Color,
) {
    Button(
        onClick = { onClick(enable) },
        modifier = modifier
            .fillMaxWidth()
            .shadow(0.dp)
            .noInteractionClickable(enabled = false) { onClick(enable) },
        elevation = ButtonDefaults.elevation(
            defaultElevation = 0.dp,
            pressedElevation = 0.dp,
            hoveredElevation = 0.dp,
            focusedElevation = 0.dp
        ),
        shape = RoundedCornerShape(28.dp),
        contentPadding = PaddingValues(15.dp),
        colors = ButtonDefaults.buttonColors(
            backgroundColor = backgroundColor,
            contentColor = fontColor
        ),
        border = BorderStroke(1.dp, MaterialTheme.colors.getButtonBorderStroke)
    ) {
        Box(
            modifier = Modifier
                .fillMaxWidth(),
            contentAlignment = Alignment.Center
        ) {
            Row(
                modifier = Modifier
                    .fillMaxWidth()
                    .align(Alignment.CenterStart)
            ) {
                Spacer(modifier = Modifier.width(4.dp))
                Icon(
                    imageVector = imageVector,
                    modifier = Modifier
                        .size(18.dp),
                    contentDescription = "drawable_icons",
                    tint = Color.Unspecified
                )
            }
            Text(
                modifier = Modifier.align(Alignment.Center),
                text = buttonText,
                color = MaterialTheme.colors.loginButtonTextColor,
                textAlign = TextAlign.Center,
                fontSize = 16.sp,
                fontFamily = FontFamily(
                    Font(
                        R.font.roboto_medium
                    )
                )
            )
        }
    }
}
0
Antony Nicolas Huaman Alikhan On

My own implementation if you want

@Composable
fun GButton() {

    val sourceImage = painterResource(id = R.drawable.ic_google)

    OutlinedButton(
        onClick = { /*TODO*/ }) {
        Row(
            verticalAlignment = androidx.compose.ui.Alignment.CenterVertically,
            modifier = Modifier.padding(horizontal = 10.dp),
        ) {
            Image(sourceImage, contentDescription = "Google Logo")
            Spacer(modifier = Modifier.width(5.dp))
            Text(
                modifier = Modifier.fillMaxWidth(),
                textAlign = TextAlign.Center,
                text = "Continue with Google",
                color = Color.Black
            )
        }

    }
}
2
Richard Onslow Roper On
Box(contentAlignment = Center){
  Icon(Modifier.align(CenterStart))

  Text()
}
0
Gabriele Mariotti On

As suggested in other answers you can wrap the content with a Box.
As alternative you can simply use the RowScope of the Button without any container.

Just apply a weight(1f) modifier to the Text and an offset(x=- iconWidth/2).

Something like:

Button(
   //....
) {

    Icon(
        imageVector = imageVector,
        modifier = Modifier.size(iconWidth),
        contentDescription = "drawable icons",
        tint = Color.Unspecified
    )
    Text(
        text = "Button",
        color = Color.Black,
        textAlign = TextAlign.Center,
        modifier = Modifier
            .weight(1f)
            .offset(x= -iconWidth/2) //default icon width = 24.dp
    )
}

enter image description here

If you want to use a Box, remove the contentAlignment = Alignment.Center in the Box and use:

 Box(modifier = Modifier.fillMaxWidth()) {
        Icon( /* ..... */ )
        Text(
            modifier = Modifier.fillMaxWidth(),
            text = "buttonText",
            textAlign = TextAlign.Center
        )
 }

enter image description here

0
God'swill Jonathan On

You can use align(Alignment.CenterStart) on the Icon's Modifier parameter to center the icon around the start of the Box Composable. This alignment will have priority over the Box's alignment parameter.

You can also delete the Spacer composable because the Box layout children are stacked one on top of the other in the composition order. So the Spacer composable is basically laying below the Text composable in the center.

If you want some space between the Icon and the Text, you could use some padding around the Icon instead.

Try this (It worked for me) :

Box(modifier = modifier.fillMaxWidth(),
        contentAlignment = Alignment.Center) {
        Icon(
            imageVector = imageVector,
            modifier = Modifier
                .size(18.dp)
                .align(Alignment.CenterStart),
            contentDescription = "drawable icons",
            tint = Color.Unspecified
        )
        Text(
            text = buttonText,
            color = Color.Black,
            textAlign = TextAlign.Center
        )
    }
0
Szymon Grochowiak On

Box doesn't provide bounds, so for longer texts, it causes overlapping. Row works better for me. Also, you can use Spacer here which is not possible for Box. In my case, I have used spacedBy as a replacement for Spacer:

Row(
    modifier = Modifier.fillMaxWidth(),
    horizontalArrangement = Arrangement.spacedBy(16.dp),
    verticalAlignment = Alignment.CenterVertically
) {
    Icon(
        painter,
        contentDescription = null
    )
    Box(
        modifier = Modifier.weight(1F),
        contentAlignment = Alignment.Center
    ) {
        Text(buttonText)
    }
}