3

I was trying to draw text inside circle and square in Jetpack Compose and I encounter this issue. The text holder/container (I am not sure what we call it), the light red rectangle, which holds the actual text, doesn't center the text drawn.

I followed this answer to draw the text exactly at the center of the circle but it still doesn't seem to be precisely at the center of the circle. As we can see, the text resides little lower part inside that light red rectangle.

As we can see in this picture, the text is already touching the lower part of the circle while we have plenty of space at the top.

Is it something to deal with the baseline? How this can be fixed?

or this is a bug?

The code:

Box(
    modifier = Modifier
        .fillMaxSize()
        .background(Color.Green.copy(alpha = 0.2f))
        .padding(36.dp),
    contentAlignment = Alignment.Center
) {
    val textMeasurer = rememberTextMeasurer()
    val textToDraw = "O"
    val style = TextStyle(
        fontSize = 328.sp,
        background = Color.Red.copy(alpha = 0.2f)
    )
    val textLayoutResult = remember(textToDraw, style) {
        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
        )
    }
}

If I make the font smaller (about 176sp in above code), it looks like below. that tells that the light red rectangle is perfectly centered within the circle but not just the text it holds.

Any help or suggestions are appreciated.

skafle
  • 627
  • 1
  • 6
  • 16

1 Answers1

2

This is probably related to the font metrics, and the uneven padding added by the platform on top of the first line and bottom of last line of your text (also know as includeFontPadding).

Why don't you try:

        val style = TextStyle(
            fontSize = 328.sp,
            background = Red.copy(alpha = 0.2f),
            platformStyle = PlatformTextStyle(includeFontPadding = false)
        )

That should give you a more accurate result:

enter image description here

Result might not be 100% perfect due to pixel exactitude and unavoidable padding in the glyph itself (the actual image used to draw the char).

Alejandra
  • 576
  • 6
  • 10
  • 1
    Thanks Alejandra for the answer. But PlatformTextStyle is deprecated. 'constructor PlatformTextStyle(Boolean = ...)' is deprecated. includeFontPadding was added to Android in order to prevent clipping issues on tall scripts. However that issue has been fixed since Android 28. Compose backports the fix for Android versions prior to Android 28. Therefore the original reason why includeFontPadding was needed is invalid on Compose.This configuration was added for migration of the apps in case some code or design was relying includeFontPadding=true behavior; and will be removed. – skafle May 03 '23 at 20:34
  • 2
    Yes sorry this might be confusing. What happened was: PlatformTextStyle constructor with includeFontPadding was created as a deprecated API to indicate this is a compatibility API, not because you should not use it. Recently we removed the deprecation with this change http://r.android.com/2534105 which will be available in next compose ui release, to encourage its usage, for example in cases like this. TY! – Alejandra May 03 '23 at 22:33
  • 1
    Thank you so much Ale again. Yeah, `includeFontPadding` does the job and as you mentioned, there are factors associated with specific fonts that will affect the shift as well. One more thing I tried is `baselineShift` inside `TextStyle`, and that helped me to fine tune the shift. Kudos. Resources to learn more: [this](https://medium.com/androiddevelopers/fixing-font-padding-in-compose-text-768cd232425b) and [this](https://fvilarino.medium.com/creating-a-ticker-board-in-jetpack-compose-dfbfe4358dd9). – skafle May 04 '23 at 19:13
  • 1
    @skafle this was as i suspected which requires some baseline calculation which should be done with `baselineShift`, good to know this. – Thracian May 10 '23 at 05:31
  • 1
    @Alejandra thanks for such a great article about text – Thracian May 10 '23 at 05:32