I am trying to draw text inside a circle in Jetpack Compose.
I drew the circle with the center being the center of the canvas.
Now I want to draw text exactly at the center of the circle.
The drawText
function inside the canvas
in Jetpack compose has topLeft
parameter which expects the Offset
of the top left corner of the rectangle holding the text. I know I can't pass the center of the circle as the topLeft
offset, and if I do, the result will look like this, which is not what I want.
I want the text to be drawn exactly at the center of the Circle.
Here is the code:
Box(
modifier = Modifier
.fillMaxSize()
.background(Color.Green.copy(alpha = 0.2f))
.padding(36.dp),
contentAlignment = Alignment.Center
) {
val textMeasurer = rememberTextMeasurer()
val textToDraw = "A"
Canvas(modifier = Modifier.fillMaxSize()) {
drawCircle(
center = Offset(
x = center.x,
y = center.y
),
radius = 350f,
color = Color.Blue,
style = Stroke(
width = 8f
)
)
drawText(
textMeasurer = textMeasurer,
text = textToDraw,
style = TextStyle(
fontSize = 150.sp,
color = Color.Black,
background = Color.Red.copy(alpha = 0.2f)
),
topLeft = Offset(
x = center.x,
y = center.y
)
)
drawPoints(
points = listOf(Offset(center.x, center.y)),
pointMode = PointMode.Points,
cap = StrokeCap.Round,
color = Color.Red,
strokeWidth = 25f
)
}
}
I can manually adjust the offset like this to make it work but this is not optimal and automatic.
topLeft = Offset(
x = center.x - 125,
y = center.y - 270
),
How can this be accomplished? Appreciate any help.
Note: The light red background I applied for the text is just to visualize the underlying rectangle being used for the text. Also I drew a point at the center of the circle to make more clear.
You can get TextLayoutResult which returns size of the rectangle that text is contained. Andy by offsetting half of the width to left and half of the height to top you can center text inside Canvas.
val textMeasurer = rememberTextMeasurer()
val textToDraw = "A"
val style = TextStyle(
fontSize = 150.sp,
color = Color.Black,
background = Color.Red.copy(alpha = 0.2f)
)
// Keys are to demonstrate that you can re-calculate block inside
// when any of them change. Otherwise remember results on each recomposition
val textLayoutResult = remember(textToDraw, style) {
textMeasurer.measure(textToDraw, style)
}
Full Sample
@Preview
@Composable
private fun DrawTextAtCenterSample() {
Box(
modifier = Modifier
.fillMaxSize()
.background(Color.Green.copy(alpha = 0.2f))
.padding(36.dp),
contentAlignment = Alignment.Center
) {
val textMeasurer = rememberTextMeasurer()
val textToDraw = "A"
val style = TextStyle(
fontSize = 150.sp,
color = Color.Black,
background = Color.Red.copy(alpha = 0.2f)
)
val textLayoutResult = remember(textToDraw) {
textMeasurer.measure(textToDraw, style)
}
Canvas(modifier = Modifier.fillMaxSize()) {
drawCircle(
center = Offset(
x = center.x,
y = center.y
),
radius = 350f,
color = Color.Blue,
style = Stroke(
width = 8f
)
)
drawText(
textMeasurer = textMeasurer,
text = textToDraw,
style = style,
topLeft = Offset(
x = center.x - textLayoutResult.size.width / 2,
y = center.y - textLayoutResult.size.height / 2,
)
)
drawPoints(
points = listOf(Offset(center.x, center.y)),
pointMode = PointMode.Points,
cap = StrokeCap.Round,
color = Color.Red,
strokeWidth = 25f
)
}
}
}