JetPack Compose Button with drawable - android

How can we achieve this in jetpack compose
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
)
}
}
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.

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

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

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

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

Box(contentAlignment = Center){
Icon(Modifier.align(CenterStart))
Text()
}

Related

IconButton's content are not centered in Jetpack Compose

I am trying to build the following component.
Following is my code,
#Composable
fun View(modifier: Modifier = Modifier){
Row(modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
horizontalArrangement = Arrangement.spacedBy(10.dp),
verticalAlignment = Alignment.CenterVertically) {
IconButton(onClick = { /*TODO*/ },
modifier = Modifier
.background(shape = roundShape, color = Color.Blue)
.size(40.dp)) {
Icon(
painter = painterResource(id = R.drawable.ic_microphone_2),
contentDescription = null,
tint = Color.White
)
}
BasicTextField(
value = "",
onValueChange = { },
modifier=Modifier
.height(40.dp)
.fillMaxWidth()
.border(1.dp,Color.Gray,roundShape)
)
}
The content of the IconButton is no longer centered after switching the LayoutDirection to Rtl.
CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Rtl) {
View()
}
this is the result of my code.
#Composable
fun IconView(modifier: Modifier = Modifier) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
horizontalArrangement = Arrangement.spacedBy(10.dp),
verticalAlignment = Alignment.CenterVertically
) {
Box(modifier = Modifier
.background(shape = RoundedCornerShape(20.dp), color = Color.Blue)
.size(50.dp).clickable {
}
){
Icon(
modifier = Modifier.align(alignment = Center),
painter = painterResource(id = android.R.drawable.ic_menu_call),
contentDescription = null,
tint = Color.White
)
}
BasicTextField(
value = "",
onValueChange = { },
modifier = Modifier
.height(40.dp)
.fillMaxWidth()
.border(1.dp, Color.Gray, RoundedCornerShape(20.dp))
)
}
}
Don't use iconButton as parent use Box and align child Icon to center. I Hope it will help you. Cheers

increase size of icon inside a button in compose

I have the following button composable
#Composable
fun AppleLoginButton(onLoginClicked: () -> Unit) {
Button(
modifier = Modifier.size(44.dp),
contentPadding = ButtonDefaults.ContentPadding,
onClick = {
onLoginClicked()
},
colors = ButtonDefaults.buttonColors(backgroundColor = Color.Black, contentColor = Color.White)
) {
Icon(
modifier = Modifier.fillMaxSize(),
painter = painterResource(id = R.drawable.ic_apple_logo), contentDescription = "Apple logo")
}
}
But I want to increase the size of the apple logo as its too small.
I have tried
modifier = Modifier.size(100.dp)
modifier = Modifier.fillMaxSize()
You can use either increase size of Button or not a height. Because it uses contentPadding which is 16.dp on both sides and leaves space. You can set it as contentPadding = PaddingValues(0.dp), have a button with no size modifier, or bigger modifier or use IconButton.
Text("Button")
Button(
modifier = Modifier.size(48.dp),
onClick = {
},
shape = RoundedCornerShape(10.dp),
colors = ButtonDefaults.buttonColors(
backgroundColor = Color.Black,
contentColor = Color.White,
),
contentPadding = PaddingValues(0.dp)
) {
Icon(
modifier = Modifier
.fillMaxSize(),
painter = painterResource(id = R.drawable.ic_baseline_star_12),
contentDescription = "Apple logo"
)
}
Text("IconButton")
IconButton(
modifier = Modifier
.size(48.dp)
.background(Color.Black, RoundedCornerShape(8.dp)),
onClick = {
}
) {
Icon(
modifier = Modifier
.fillMaxSize(),
painter = painterResource(id = R.drawable.ic_baseline_star_12),
contentDescription = "Apple logo",
tint = Color.White
)
}
Text("IconButton clip or shadow with clip=true ,0.dp elevation")
IconButton(
modifier = Modifier
.clip(RoundedCornerShape(8.dp))
// .shadow(0.dp, RoundedCornerShape(8.dp), clip = true)
.size(48.dp)
.background(Color.Black),
onClick = {
}
) {
Icon(
modifier = Modifier
.fillMaxSize(),
painter = painterResource(id = R.drawable.ic_baseline_star_12),
contentDescription = "Apple logo",
tint = Color.White
)
}

How to make Compose Text wrap container size

I have some Column with Icon and Text inside. Column is wrap the size of Text but i want to Column wrap Icon and long text move to another line
How It's looks now
How I want it to look like
#Composable
fun ServiceItem(
service: Service,
onItemClick: (service: Service) -> Unit
) {
Column(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Card(
modifier = Modifier.padding(horizontal = 16.dp),
shape = RoundedCornerShape(itemBackgroundCornerSize),
backgroundColor = colorResource(id = R.color.gray)
) {
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.size(itemSize)
.clickable(onClick = {
onItemClick(service)
})
) {
Image(
painter = rememberAsyncImagePainter(service.imageUrl),
contentDescription = null,
modifier = Modifier.padding(iconPadding)
)
}
}
Text(
text = service.title,
textAlign = TextAlign.Center,
style = itemTitleTextDefaultStyle(),
modifier = Modifier.padding(top = textTopPadding)
)
}
}

Jetpack Compose Textfield Alignment

I'm new to jetpack compose. I want to start typing from TextField's centervertically-start
position but I can't put "Example" to center
vertically-start position.
Row(
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.shadow(5.dp)
.background(Color.Yellow),
) {
BasicTextField(
value = text,
onValueChange = {onvalueChange(it)},
modifier = Modifier.weight(10f).background(Color.Blue).fillMaxSize(),
singleLine = true,
textStyle = LocalTextStyle.current.copy(
textAlign = TextAlign.Center
)
)
Image(painter = painterResource(id = R.drawable.ic_baseline_search_24),
contentDescription = "Search",
modifier = Modifier.weight(2f).fillMaxSize()
)
This is my code
And this is what I want to do.
Row has a verticalAlignment for this. Also, if you want your TextField left align like the picture, remove the textAlign (or change it but it default to start)
Row(
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.shadow(5.dp)
.background(Color.Yellow),
verticalAlignment = Alignment.CenterVertically,
) {
BasicTextField(
value = text,
onValueChange = {onvalueChange(it)},
modifier = Modifier.weight(10f).background(Color.Blue).fillMaxSize(),
singleLine = true,
)
Image(painter = painterResource(id = R.drawable.ic_baseline_search_24),
contentDescription = "Search",
modifier = Modifier.weight(2f).fillMaxSize()
)
}
Use background box to control, please try:
Row(
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.shadow(5.dp)
.background(Color.Yellow),
) {
Box(Modifier.weight(10f).background(Color.Blue).fillMaxSize(),contentAlignment = CenterStart){
BasicTextField(
value = text,
onValueChange = { onvalueChange(it) },
modifier = Modifier.wrapContentHeight(
Alignment.CenterVertically),
singleLine = true,
textStyle = LocalTextStyle.current.copy(
textAlign = TextAlign.Start
)
)
}
Image(
Icons.Filled.Search,
contentDescription = "Search",
modifier = Modifier.weight(2f).fillMaxSize()
)
}

How to get Image with text on top/infront? (Google Classroom Home Image Format)

I want to make an Image with Text on top, just like Google CLassroom. But first I want to test Image and then Text. Instead, I got the image overlapping the text. Image Overlapping text
Then I move the Image code after the text. How to get simple G classroom format
Text then Image
#Composable
fun ClassImage(
// icon: VectorAsset,
// label: String,
// modifier: Modifier = Modifier
) {
val imageAlpha = 1f
Surface(
modifier = Modifier
.padding(start = 8.dp, top = 8.dp, end = 8.dp)
.fillMaxWidth(),
color = colors.primary.copy(alpha = 0.12f)
) {
TextButton(
onClick = {},
modifier = Modifier.fillMaxWidth()
) {
Row(
horizontalArrangement = Arrangement.Start,
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth())
{
Image(
imageResource(id = R.drawable.class1),
alpha = imageAlpha
)
Column {
Text("Alfred Sisley", fontWeight = FontWeight.Bold)
ProvideEmphasis(emphasis = EmphasisAmbient.current.medium) {
Text("3 minutes ago", style = MaterialTheme.typography.body2)
}
}
}
}
}
}
To put Text on top of the Image you can use Box, which is similar to old FrameLayout.
I'm not sure want you wanted to achieve, but if smth like this:
Then you can do it this way:
Surface(
shape = RoundedCornerShape(8.dp),
modifier = Modifier
.preferredHeight(128.dp)
.clickable(onClick = {})
) {
Box {
Image(
vectorResource(id = R.drawable.ic_launcher_background),
alpha = imageAlpha,
contentScale = ContentScale.Crop,
modifier = Modifier.fillMaxSize()
)
Column(modifier = Modifier.padding(16.dp)) {
Text(
"Alfred Sisley",
fontWeight = FontWeight.Bold,
style = MaterialTheme.typography.h6)
ProvideEmphasis(emphasis = EmphasisAmbient.current.medium) {
Text("3 minutes ago", style = MaterialTheme.typography.body2)
}
Spacer(modifier = Modifier.weight(1f))
Text(text = "Footer", style = MaterialTheme.typography.body1)
}
}
}
With 1.0.0-beta02 you can use a Box as parent container.
Something like:
Box(modifier = Modifier.height(IntrinsicSize.Max))
{
Image(
painterResource(id = R.drawable.xx),
"contentDescription",
alpha = 0.8f,
modifier = Modifier.requiredHeight(100.dp)
)
Column(
modifier = Modifier.fillMaxHeight(),
verticalArrangement = Arrangement.Bottom) {
Text("Alfred Sisley",
fontWeight = FontWeight.Bold)
CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.medium) {
Text("3 minutes ago", style = MaterialTheme.typography.body2)
}
}
}

Categories

Resources