How do I separate text and icon in TextButton to make it like whatsapp settings
Row(
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
) {
TextButton(
onClick = { /*TODO*/ },
modifier = Modifier.fillMaxSize(),
) {
Text(text = "$name")
Icon(
imageVector = Icons.Filled.KeyboardArrowRight,
contentDescription = "",
modifier = Modifier.size(40.dp)
)
}
}
It shows
But I want to like this
I try Spacer and Padding but it didn't work because I have
fun SettingsButtons(name: String)
#Composable
fun SettingsButtons(name: String) {
Row(
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
) {
TextButton(
onClick = { /*TODO*/ },
modifier = Modifier.fillMaxSize(),
) {
Text(text = "$name")
Icon(
imageVector = Icons.Filled.KeyboardArrowRight,
contentDescription = "",
modifier = Modifier.size(40.dp)
)
}
}
}
And based on the parameter that I passed {name} the text will be changed
SettingsButtons(name = "Account")
SettingsButtons(name = "Order History")
SettingsButtons(name = "Favorite")
so I think that why Spacer and Padding didn't work because the text size is different or I am not using it correctly
The content of a TextButton is a RowScope.
You can apply a weight(1f) modifier to the Text
TextButton(
onClick = { /*TODO*/ },
modifier = Modifier.fillMaxWidth(),
) {
Text(text = "Name", modifier = Modifier.weight(1f))
Icon(
imageVector = Icons.Filled.KeyboardArrowRight,
contentDescription = "",
modifier = Modifier.size(40.dp)
)
}
Try RaisedButton with a Row as Child and in Row add Text and Icon widget
RaisedButton(
onPressed: () {},
child: Row(
children: <Widget>[
Text(
'Button'),
Icon(
Icons.arrow_forward,
color: Colors.white,
))
I think what you are looking for is Arrangement. You could try to use Arrangement like this:
Row(modifier = Modifier.fillMaxWidth().height(50.dp)) {
TextButton(
onClick = { /*TODO*/ },
modifier = Modifier.fillMaxWidth(),
Arrangement.SpaceBetween
) {
Text(text = "$name")
Icon(
imageVector = Icons.Filled.KeyboardArrowRight,
contentDescription = "",
modifier = Modifier.size(40.dp)
)
}
}
I found this question which is quite similiar to your problem but in a vertical direction:
Filling remaining space with Spacer on Jetpack Compose
Further I will link you the documentation where you can find more info about alignment and arrangement in jetpack compose.
https://developer.android.com/reference/kotlin/androidx/compose/foundation/layout/Arrangement
Related
I am trying to achieve the below layout
enter image description here
There is no way to set individual border width in jetpack compose
This is my code
Row(
modifier = Modifier
.border(width = 1.dp, shape = RoundedCornerShape(4.dp), color = Purple3)
.padding(10.dp),
verticalAlignment = Alignment.CenterVertically
) {
Image(
painter = painterResource(id = R.drawable.info),
contentDescription = stringResource(id = R.string.long_press_an_item),
)
Text(
text = stringResource(id = R.string.long_press_an_item),
fontFamily = FontFamily(Font(R.font.inter_medium)),
fontSize = 12.sp,
color = Gray5,
modifier = Modifier.padding(horizontal = 10.dp)
)
}
I used different colors, but you can see the result:
I see there three ways, how you can achieve this effect:
You can create custom modifier extension method, as I did in one my project, using drawBehind Modifier:
#Preview
#Composable
fun Preview() {
Row(
modifier = Modifier
.someCustomOutline(
outlineColor = MaterialTheme.colors.primary,
surfaceColor = MaterialTheme.colors.surface,
startOffset = 3.dp,
outlineWidth = 1.dp,
radius = 4.dp
)
.padding(10.dp),
verticalAlignment = Alignment.CenterVertically
) {
Image(
imageVector = Icons.Default.Info,
contentDescription = null,
)
Text(
text = "long_press_an_item",
fontSize = 12.sp,
modifier = Modifier.padding(horizontal = 10.dp)
)
}
}
#Composable
fun Modifier.someCustomOutline(
outlineColor: Color,
surfaceColor: Color,
startOffset: Dp,
outlineWidth: Dp,
radius: Dp = 1.dp
) = drawBehind {
val startOffsetPx = startOffset.toPx()
val outlineWidthPx = outlineWidth.toPx()
val radiusPx = radius.toPx()
drawRoundRect(
color = outlineColor,
topLeft = Offset(0f, 0f),
size = size,
cornerRadius = CornerRadius(radiusPx, radiusPx),
style = Fill
)
drawRoundRect(
color = surfaceColor,
topLeft = Offset(startOffsetPx, outlineWidthPx),
size = Size(size.width - startOffsetPx - outlineWidthPx, size.height - outlineWidthPx * 2),
cornerRadius = CornerRadius(radiusPx - outlineWidthPx, radiusPx - outlineWidthPx),
style = Fill
)
}
Usage:
this is very bad approach, but I will mention it for just in case
You can just frap your element with Box and add padding to it:
Box(
modifier = Modifier
.background(shape = RoundedCornerShape(4.dp), color = Purple3)
.padding(start = 3.dp, top = 1.dp, end = 1.dp, bottom = 1.dp)
) {
Row(
modifier = Modifier
.background(MaterialTheme.colors.surface, shape = RoundedCornerShape(3.dp))
.padding(10.dp),
verticalAlignment = Alignment.CenterVertically
) {
Image(
imageVector = painterResource(id = R.drawable.info),
contentDescription = stringResource(id = R.string.long_press_an_item),
)
Text(
text = stringResource(id = R.string.long_press_an_item),
fontSize = 12.sp,
fontFamily = FontFamily(Font(R.font.inter_medium)),
color = Gray5,
modifier = Modifier.padding(horizontal = 10.dp)
)
}
}
This can be done using a Box with background as your border and adding padding more padding to start than other corners
#Preview
#Composable
private fun Test() {
Box(modifier = Modifier.background(Color(0xffBA68C8), RoundedCornerShape(4.dp))) {
Row(
modifier = Modifier
.padding(start = 4.dp, top = 1.dp, bottom = 1.dp, end = 1.dp)
.background(Color.White, RoundedCornerShape(4.dp))
.padding(10.dp),
verticalAlignment = Alignment.CenterVertically
) {
Image(
imageVector = Icons.Default.Info,
contentDescription = "Long press item to enable multi-select and bulk operations"
)
Text(
text = "Long Press on Item",
fontSize = 12.sp,
color = Color.Gray,
modifier = Modifier.padding(horizontal = 10.dp)
)
}
}
}
Container(
decoration: BoxDecoration(
gradient: LinearGradient(stops: const [
0.014,
0.014
], colors: [
isError ? redColor : greenColor,
Theme.of(context).colorScheme.background
]),
color: Theme.of(context).colorScheme.background,
borderRadius: BorderRadius.circular(10),
border: Border.all(color: isError ? redColor : greenColor, width: 1),
),
padding: const EdgeInsets.symmetric(
vertical: 12,
horizontal: 12,
),
child: Row(
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: Text(
text,
style: GoogleFonts.inter(
fontWeight: FontWeight.w500,
fontSize: 12,
color: gray6Color,
),
),
)
],
)
I expected the following code to show The map on the top and two text fields at the bottom. Instead, the map is taking all available space.
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(10.dp),
modifier = Modifier.fillMaxWidth(),
) {
GoogleMap(
cameraPositionState = cameraPositionState
) {
Marker(
position = singapore,
title = "Singapore",
snippet = "Marker in Singapore"
)
}
TextField(
value = "",
onValueChange = {},
label = { Text(text = "Load Location") },
modifier = Modifier.fillMaxSize()
)
TextField(
value = "",
onValueChange = {},
label = { Text(text = "Unload Location") },
modifier = Modifier.fillMaxSize()
)
}
Ever heard of the weight modifier?
I'm trying to center the icon and trailing elements vertically using a ListItem. I'm not sure if it is possible or I need to drop the ListItem and use a combination of column/row instead.
I'm using something like:
ListItem(
Modifier.clickable(onClick = onClick),
icon = {
Box(
modifier = Modifier.fillMaxHeight(), contentAlignment = ALignment.Center
) {
Text(
text = dateUtil.formatTime(item.startTime),
style = TextStyle(
color = SnyDarkBlue,
fontSize = 14.sp,
fontFamily = oswaldFamily,
fontWeight = FontWeight.Bold,
letterSpacing = (-0.25).sp,
),
)
}
},
thanks in advance!
You can center both the icon and text sections using a Column:
ListItem(
modifier = Modifier
.fillMaxWidth()
.requiredHeight(50.dp)
.background(color = Color.Gray),
icon = {
Column(
modifier = Modifier
.fillMaxHeight(), verticalArrangement = Arrangement.Center
) {
Text(
text = "06:00 PM"
)
}
},
text = {
Column(
modifier = Modifier
.fillMaxHeight(), verticalArrangement = Arrangement.Center
) {
Text("Your item text goes here")
}
},
)
I want to set the "Account" text to the center of TopAppBar and add an icon to the right of TopAppBar, how can I do it?
Scaffold(
scaffoldState = scaffoldState,
topBar = {
TopAppBar(
title = {
Text(
text = stringResource(R.string.account),
style = AppFont.PoppinsTypography.subtitle1
)
},
navigationIcon = {
Icon(
painter = painterResource(id = R.drawable.ic_left),
contentDescription = "back", tint = AppColor.brandColor.BLUE_DE_FRANCE
)
}, actions = {
viewModel.navigateUp()
}, backgroundColor = AppColor.neutralColor.DOCTOR
)
},
)
To align the title text to the center of TopAppbar,
Update
Using Material 3
CenterAlignedTopAppBar(
title = {
Text(
text = stringResource(R.string.account),
style = AppFont.PoppinsTypography.subtitle1
)
},
)
And actions attribute should have the compoosables to add at the end. Use that to add an icon to the right of TopAppBar.
Example,
actions = {
IconButton(onClick = { /*TODO*/ }) {
Icon(
imageVector = Icons.Rounded.ShoppingCart,
contentDescription = "cart",
)
}
},
The old answer, using Material 2
Change title to this,
title = {
Text(
text = stringResource(R.string.account),
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth(),
style = AppFont.PoppinsTypography.subtitle1
)
},
You could just implement a custom layout
#Composable
fun TopBar() {
Scaffold(
topBar = {
Layout(
modifier = Modifier.fillMaxHeight(0.1f), //Fills one-tenth of the screen
content = {
Text("Account")
Icon(
imageVector = Icons.Default.ArrowBack,
contentDescription = "back",
tint = Color.Blue,
)
}
) { measurables, constraints ->
val title = measurables[0].measure(constraints)
val navigationIcon = measurables[1].measure(constraints)
layout(constraints.maxWidth, constraints.maxHeight) {
title.place(
(constraints.maxWidth - title.width) / 2, //Midway
constraints.maxHeight / 2 // Usually Texts acquire maxHeight so we did not need t subtract
)
navigationIcon.place(
(constraints.maxWidth - 1.5 * navigationIcon.width).roundToInt(), //1.5 to add a bit of extra padding from the edge
(constraints.maxHeight - navigationIcon.height) / 2
)
}
}
},
) {
}
}
In Compose, you can align center all composables in a Column widget by doing the following:
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = "First item",
modifier = Modifier.padding(16.dp)
)
Text(
text = "Second item",
modifier = Modifier.padding(16.dp)
)
Text(
text = "Third item",
modifier = Modifier.padding(16.dp)
)
}
However, what if I only want to center the first composable?
I think this should work for you
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = "First item",
modifier = Modifier.padding(16.dp)
)
Text(
text = "Second item",
modifier = Modifier.padding(16.dp).fillMaxWidth()
)
Text(
text = "Third item",
modifier = Modifier.padding(16.dp).fillMaxWidth()
)
}