You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jetpack Compose精准绘制文本问题:文本无法居中于容器

Jetpack Compose Canvas文本圆形居中问题修复

问题原因

你遇到的问题确实和文本基线以及字体的ascent/descent属性有关:

  • textLayoutResult.size.height是文本容器的总高度,包含了字体的上间距(leading)、上升高度(ascent)、下降高度(descent)等冗余空间,并非字符本身的视觉高度。
  • 多数字体的字形重心和容器中心不重合,比如大写字母"O"的视觉中心会比容器中心偏上,但你用容器高度的一半计算偏移,反而让字符整体偏下。

修复方案

核心是基于文本的实际视觉边界而非容器高度计算偏移,有两种可靠实现方式:

方式1:利用文本的基线与视觉偏移计算

通过textLayoutResult的ascent和descent属性,直接计算字符的视觉中心偏移:

drawText(
    textMeasurer = textMeasurer,
    text = textToDraw,
    style = style,
    topLeft = Offset(
        x = center.x - textLayoutResult.size.width / 2,
        // 视觉中心偏移:baseline到中心的距离为 (ascent + descent)/2,ascent为负数,descent为正数
        y = center.y - (textLayoutResult.ascent + textLayoutResult.descent) / 2
    )
)

方式2:获取字符的精确边界框

通过getBoundingBox(0)获取单个字符的实际绘制边界,用边界框的中心来对齐:

val charBounds = textLayoutResult.getBoundingBox(0)
drawText(
    textMeasurer = textMeasurer,
    text = textToDraw,
    style = style,
    topLeft = Offset(
        x = center.x - charBounds.width / 2 - charBounds.left,
        y = center.y - charBounds.height / 2 - charBounds.top
    )
)

修改后的完整代码示例

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 = center,
            radius = 350f,
            color = Color.Blue,
            style = Stroke(width = 8f)
        )
        // 使用方式1的计算逻辑
        drawText(
            textMeasurer = textMeasurer,
            text = textToDraw,
            style = style,
            topLeft = Offset(
                x = center.x - textLayoutResult.size.width / 2,
                y = center.y - (textLayoutResult.ascent + textLayoutResult.descent) / 2
            )
        )
        drawPoints(
            points = listOf(center),
            pointMode = PointMode.Points,
            cap = StrokeCap.Round,
            color = Color.Red,
            strokeWidth = 25f
        )
    }
}

效果说明

调整后,字符"O"的视觉中心会和圆形中心(红色圆点)精准对齐,无论字体大小如何变化,都能保持居中状态,不会出现上下偏移的问题。

内容的提问来源于stack exchange,提问作者skafle

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 23:42:32