I need to insert a Text element Text("text center")
in the center of the screen (both horizontally and vertically). Also, I want to insert the Text("text")
element above Text("text center")
with a blank space of 32dp
:
So for example the following code is not correct because the whole block is centered and not just "text center":
Column(
modifier = Modifier
.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center,
) {
Text(text = "text")
Spacer(modifier = Modifier.height(32.dp))
Text(text = "text center")
}
CodePudding user response:
You can use the ConstraintLayout
since this type of layout would be a bit cumbersome to do properly with just the composables from the standard library.
ConstraintLayout can help place composables relative to others on the screen, and is an alternative to using multiple nested Row, Column, Box and custom layout elements.
Add this to your app.gradle
file
implementation "androidx.constraintlayout:constraintlayout-compose:1.0.1"
and sync the project so that Gradle downloads the dependency.
As of July 2022 the stable version is 1.0.1
.
Your layout needs the following constraints:
- the "center text" needs to center horizontally and vertically to the parent
- the "top text" needs to center horizontally to the parent
- there should be a margin of
32 dp
between the bottom of "top text" and the top of "center text"
In code these constraints are specified like this
ConstraintLayout(
modifier = Modifier.fillMaxSize() // copied from your example
) {
// Create references for the composables to constrain
val (topText, centerText) = createRefs()
Text(
text = "text",
modifier = Modifier.constrainAs(topText) {
// the "top text" needs to center horizontally to the parent
centerHorizontallyTo(parent)
// there should be a margin of 32 dp between the bottom
// of "top text" and the top of "center text"
bottom.linkTo(centerText.top, margin = 32.dp)
}
)
Text(
text = "text center",
modifier = Modifier.constrainAs(centerText) {
// the "center text" needs to center horizontally and
// vertically to the parent
centerHorizontallyTo(parent)
centerVerticallyTo(parent)
}
)
}
Since the official documentation on the compose version of ConstraintLayout
is really limited, you can check the compose samples that are using it if you need more examples.
The official documentation for the Widget (non-compose) version of ConstraintLayout
is good though, so to learn about everything that it can do, you can check https://developer.android.com/reference/androidx/constraintlayout/widget/ConstraintLayout.
Maybe some of the functionality might not be available in the compose version yet. As of July 2022 the latest alpha version is 1.1.0-alpha03
implementation "androidx.constraintlayout:constraintlayout-compose:1.1.0-alpha03"
CodePudding user response:
This can be done in many ways.
Option one using a custom Layout
@Composable
private fun TextLayout(
modifier: Modifier,
padding: Dp = 32.dp,
content: @Composable () -> Unit
) {
val density = LocalDensity.current
val paddingInPx = with(density) { padding.roundToPx() }
Layout(modifier = modifier, content = content) { measurables, constraints ->
require(measurables.size == 2)
val placeables: List<Placeable> = measurables.map { measurable: Measurable ->
measurable.measure(constraints.copy(minWidth = 0, minHeight = 0))
}
val topPlaceable = placeables.first()
val centerPlaceable = placeables.last()
val height = centerPlaceable.height
val totalHeight = constraints.maxHeight
val verticalCenter = (totalHeight - height)/2
layout(constraints.minWidth, totalHeight) {
centerPlaceable.placeRelative(0, verticalCenter)
topPlaceable.placeRelative(0, verticalCenter - height - paddingInPx)
}
}
}
Option 2 Using a Box and getting height of text using onTextLayout callback of Text.
Box(
modifier = Modifier
.fillMaxHeight()
.border(3.dp, Color.Red),
contentAlignment = Alignment.CenterStart
) {
val density = LocalDensity.current
var textHeight by remember { mutableStateOf(0.dp) }
Text(
"TextCenter",
fontSize = 20.sp,
onTextLayout = {
textHeight = with(density) {
it.size.height.toDp()
}
}
)
Text(
text = "Text",
modifier = Modifier.padding(bottom = 64.dp textHeight * 2),
color = Color.Blue,
fontSize = 20.sp
)
}
But this option, it's only for demonstration, will have another recomposition since we update var textHeight by remember { mutableStateOf(0.dp) }
Option 3 is using a ConstraintLayout. For a simple layout that like this i don't think anyone counter any performance issues using ConstraintLayout
but i always refrain using ConstraintLayout
because it uses MultiMeasureLayout
that comes with a serious warning
@Deprecated(
"This API is unsafe for UI performance at scale - using it incorrectly will lead "
"to exponential performance issues. This API should be avoided whenever possible."
)
fun MultiMeasureLayout(
modifier: Modifier = Modifier,
content: @Composable @UiComposable () -> Unit,
measurePolicy: MeasurePolicy
) {
}