JetPack Compose Button with drawable
M

6

11

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.

Marinelli answered 22/5, 2022 at 10:58 Comment(5)
Thank you, I've been waiting for a sensible question for longer than you'd imagine.Glaswegian
try adding Modifier.align(Alignment.CenterStart) to Icon and Modifier.align(Alignment.Center) to Text .Secondhand
not working throwing Required: Alignment.VerticalMarinelli
@DheerajGupta Are you sure you still using Box not a Row as suggested in the below answer? When you need to layout one item at center and an other one in some side/corner, using Box is the correct way. Also you also can safely remove Spacer as it has no effect with BoxLilly
What do you say, "Pylyp"?Glaswegian
M
9
@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
                    )
                )
            )
        }
    }
}
Marinelli answered 9/8, 2022 at 11:15 Comment(1)
A code-only answer is not high quality. While this code may be useful, you can improve it by saying why it works, how it works, when it should be used, and what its limitations are. Please edit your answer to include explanation and link to relevant documentation.Cerebroside
C
10

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

Cookhouse answered 23/5, 2022 at 7:12 Comment(0)
M
9
@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
                    )
                )
            )
        }
    }
}
Marinelli answered 9/8, 2022 at 11:15 Comment(1)
A code-only answer is not high quality. While this code may be useful, you can improve it by saying why it works, how it works, when it should be used, and what its limitations are. Please edit your answer to include explanation and link to relevant documentation.Cerebroside
A
4

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
        )
    }
Angleworm answered 22/5, 2022 at 23:2 Comment(0)
P
1

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)
    }
}
Pinson answered 8/8, 2022 at 12:4 Comment(0)
H
0

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
            )
        }

    }
}
Hypanthium answered 23/10, 2023 at 1:34 Comment(0)
G
-2
Box(contentAlignment = Center){
  Icon(Modifier.align(CenterStart))

  Text()
}
Glaswegian answered 22/5, 2022 at 11:2 Comment(2)
If I'm using a spaceBetween then the text is going in right not getting center tried thatMarinelli
What are you talking about?Glaswegian

© 2022 - 2024 — McMap. All rights reserved.