Reputation: 1193
I am working on my first app fully designed by Compose.
I need to centralize vertically text with the Text()
compose component. In traditional Android dev practice I did this over alignment property. Text()
compose also has alignment property, but at this moment it has limited capacity (Alignment.Horizontal()
is only allowed), despite on I noticed different alignment values within Text()
when made a research in web. Similar case for Column()
- it also has alignment property .wrapContentSize()
and also has limitation on values that could be used here, despite on quick research in web shows it may receive CenterVertically
too.
What is your way to achieve this visual effect? The full code piece is below
@ExperimentalUnitApi
@Composable
fun TripBookingContent(state: PassengerTripUiState.TripBookUiState) {
Log.d(App.TAG, "[screen] TripBookingContent")
val baselineGrid = dimensionResource(id = R.dimen.baseline_grid)
val mainPadding = dimensionResource(id = R.dimen.main_margin_compact)
var componentSpace = dimensionResource(id = R.dimen.component_space)
Column(
modifier = Modifier
.wrapContentHeight()
.fillMaxWidth()
.padding(
paddingValues = PaddingValues(
horizontal = mainPadding,
vertical = baselineGrid
)
)
) {
TripViewItem(
data = state.trip,
{},
modifier = Modifier.padding(vertical = baselineGrid)
)
Text(
text = stringResource(id = R.string.booking_screen_driver),
color = colorResource(id = R.color.white),
style = TextStyle(textIndent = TextIndent(firstLine = TextUnit(16F, TextUnitType.Sp))),
modifier = Modifier
.height(componentSpace)
.padding(start = baselineGrid)
.fillMaxWidth()
.background(color = colorResource(id = R.color.design_default_color_secondary_variant))
)
Log.d(App.TAG, "[state] state.driver - ${state}")
Log.d(App.TAG, "[state] state.driver.toDriver() - ${state.driver}")
DriverCardContent(data = state.driver)
Text(
text = stringResource(id = R.string.booking_screen_msg),
color = colorResource(id = R.color.white),
style = TextStyle(textIndent = TextIndent(firstLine = TextUnit(16F, TextUnitType.Sp))),
textAlign = TextAlign.Center,
modifier = Modifier
// .height(componentSpace)
.height(32.dp)
.padding(start = baselineGrid)
.fillMaxWidth()
.background(color = colorResource(id = R.color.colorPrimaryDark))
)
/**
* Disable book button at current (alfa version), for more details
* */
Button(
onClick = { /* no op */ },
modifier = Modifier
.alpha(0F)
.fillMaxWidth()
.padding(baselineGrid)
.height(dimensionResource(id = R.dimen.button_height)),
colors = ButtonDefaults.buttonColors(
backgroundColor = Color.Blue,
contentColor = Color.White
),
) {
Text(
text = stringResource(id = R.string.booking_screen_confirm_button),
modifier = Modifier.align(Alignment.CenterVertically),
fontWeight = FontWeight.Bold
)
}
}
}
UPDATE My final solution become this one below. I have to move padding and background to the Box() layer to achieve text in center both vertically and horizontally.
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.height(32.dp)
.padding(start = baselineGrid)
.fillMaxWidth()
.background(color = colorResource(id = R.color.colorPrimaryDark))
) {
Text(
text = stringResource(id = R.string.booking_screen_msg),
color = colorResource(id = R.color.white),
style = TextStyle(textIndent = TextIndent(firstLine = TextUnit(16F, TextUnitType.Sp))),
textAlign = TextAlign.Center,
/* modifier = Modifier
// .height(componentSpace)
.height(32.dp)
.padding(start = baselineGrid)
.fillMaxWidth()
.background(color = colorResource(id = R.color.colorPrimaryDark))*/
)
}
Upvotes: 63
Views: 50430
Reputation: 2835
Try this
@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
Surface(modifier.fillMaxSize(), color = Color.LightGray) {
Text(
text = "Hello $name!",
modifier = modifier.wrapContentHeight(align = Alignment.CenterVertically),
textAlign = TextAlign.Center,
fontSize = 40.sp
)
}
}
Upvotes: 2
Reputation: 2196
I acknowledge I am suggesting is an utterly hideous solution from the perspective of following best practices, but in this situation, I felt certain I was tempting fate when I tried "correct" approach mentioned in other answers, ultimately giving up when I had to tweak dp numbers to fix alignment issues. This struck me as the "future-volatile" (the opposite of future proof). I didn't trust JetpackCompose to not change how it was going to handle this problem, and I didn't exactly trust myself (A Jetpack newbie at the time) to anticipate every possible way a user could break it.
That, and sooner or later there was going to be a "right and proper" way to handle this that was going to be complete different.
So I went with the string manipulation approach, creating a function that generated a newline char after each one in the string that is to be displayed vertically. It can even be made sensitive to languages and screen-reading utilities for the visually impaired where this shouldn't happen. The i18n and disability aspects of that seemed far more straightforward than trying to second guess this.
Upvotes: 0
Reputation: 1001
It is possible to center text vertically IF your Text widget has a height modifier for example - Text(text="example", modifier=Modifier.height(100.dp)
You can use the wrapContentHeight
modifier to align text vertically for example
Text(
text = "Example",
modifier = Modifier.width(100.dp)
.height(100.dp)
.background(color = Color.Cyan)
.wrapContentHeight(align = Alignment.CenterVertically),
color = Color.Black,
fontSize = 42.sp,
textAlign = TextAlign.Right
)
Upvotes: 100
Reputation: 15
For centering the text in a Text you can also use TextStyle, example:
val body = TextStyle(
fontSize = 16.sp,
lineHeight = 22.sp,
lineHeightStyle = LineHeightStyle(
alignment = LineHeightStyle.Alignment.Proportional,
trim = LineHeightStyle.Trim.None
)
)
LineHeightStyle you can set its alignment and trim.
TextAlign doesnt work with aligning Vertically, however in here you can.
Upvotes: 1
Reputation: 67268
This can be done in several ways. As mentioned in other answer you can use Modifier.wrapContentSize()
, Modifier.layout
which is very similar to how wrapContentSize modifier implemented , it's how size Modifers are implemented, they basically change, update or limit Constraints and measure and layout their contents.
Modifier.wrapContentSize
changes
minimum width and height to 0, and because of that you would be able measure content in that range instead of size Modifier or Constraints that return fixed min,max width range. such as min=200.dp, max=200.dp. If you change min range to 0 your content gets measured with it's actual content dimensions and it gets placed in any aligment.
@Preview
@Composable
private fun Test() {
Text(
text = "Hello world",
modifier = Modifier
.border(2.dp, Color.Red)
.size(200.dp)
.layout { measurable, constraints ->
val placeable =
measurable.measure(
// This is how wrapContent works
constraints.copy(minWidth = 0, minHeight = 0)
)
layout(constraints.maxWidth, constraints.maxHeight) {
// This is how wrapContent alignment works
val x = (constraints.maxWidth - placeable.width) / 2
val y = (constraints.maxHeight - placeable.height) / 2
placeable.placeRelative(x, y)
}
},
textAlign = TextAlign.Center
)
}
or use Box()
with contentAlignment = Alignment.Center
. There are also CenterStart and CenterEnd options for alignment either.
Box(
contentAlignment = Alignment.Center,
) {
Text(
text = "Text",
textAlign = TextAlign.Center
)
}
Upvotes: 48
Reputation: 7690
Alignment modifiers depend on the parent, which is how it supposed to be, in a vertical list (column) vertical alignment is handled by the parent (which is great that compose can enforce this)
Soo in your case you probably need a different hierarchy. For ex: Box
instead of Column
. Alternatively you can play around with the size of the Text
, make it 200dp
in height for example and use textAlign
, to center it's text.
For reference:
Box(contentAlignment = Alignment.Center)
-> Specifies alignment of childrenText(text = "example", modifier = Modifier.wrapContentSize().align())
-> Specifies alignment of Text
composable under parentText(text = "example", textAlign = TextAlign.Center)
-> specifies alignment of text, inside composable, using this with wrapContentSize()
won't have any effect, since the Composable has the same size as it's content textUpvotes: 11