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

Canvas中drawText如何结合高度实现矩形内文本居中?

解决矩形内文本居中且自适应字号的问题

你的核心问题是测量文本时未限制宽度,默认计算的是单行文本的宽高,导致宽度缩放因子被拉得极低,字号过度缩小,同时文本没有机会自动换行。下面是修正后的实现逻辑:

问题分析

原代码中textMeasurer.measure(text, ...)未设置宽度约束,返回的是单行文本的尺寸。当文本较长时,单行宽度远大于矩形宽度,计算出的widthScaleFactor会非常小,直接导致字号被缩到极小,完全没利用矩形的垂直空间让文本换行。

修正后的代码

private fun DrawScope.drawBoundingBox(boundingBox: Rect, text: String, textMeasurer: TextMeasurer) {
    val defaultFontSize = 14.sp
    val fontFamily = FontFamily(Font(R.font.comic_sans))
    val minFontSize = 8.sp // 设置最小字号,避免缩得过小
    val paddingHorizontal = 6f // 矩形内水平边距
    val paddingVertical = 10f // 矩形内垂直边距

    // 计算文本可用的实际宽高(减去内边距)
    val availableWidth = boundingBox.width().toFloat() - 2 * paddingHorizontal
    val availableHeight = boundingBox.height().toFloat() - 2 * paddingVertical

    var currentFontSize = defaultFontSize
    var textLayoutResult: TextLayoutResult

    // 循环调整字号,直到文本适配可用空间或达到最小字号
    do {
        val textStyle = TextStyle(
            fontSize = currentFontSize,
            fontFamily = fontFamily,
            color = Color.Black,
            textAlign = TextAlign.Center,
            fontWeight = FontWeight.Bold,
        )
        // 用宽度约束测量文本(允许自动换行)
        textLayoutResult = textMeasurer.measure(
            text = text.uppercase(),
            style = textStyle,
            constraints = Constraints(maxWidth = availableWidth.toInt())
        )
        // 如果当前文本高度超过可用高度,缩小字号
        if (textLayoutResult.size.height > availableHeight && currentFontSize > minFontSize) {
            currentFontSize = (currentFontSize.value * 0.95f).sp // 逐步缩小,避免跳变
        } else {
            break
        }
    } while (currentFontSize > minFontSize)

    // 绘制背景矩形
    drawRoundRect(
        color = Color.White,
        topLeft = Offset(boundingBox.left.toFloat(), boundingBox.top.toFloat()),
        size = Size(boundingBox.width().toFloat() + 12f, boundingBox.height().toFloat() + 20f),
        cornerRadius = CornerRadius(2.dp.toPx(), 2.dp.toPx()),
    )

    // 计算文本居中的偏移量(水平+垂直居中)
    val textX = boundingBox.left.toFloat() + paddingHorizontal + (availableWidth - textLayoutResult.size.width) / 2
    val textY = boundingBox.top.toFloat() + paddingVertical + (availableHeight - textLayoutResult.size.height) / 2 + textLayoutResult.firstBaseline

    // 绘制居中的文本
    drawText(
        textMeasurer = textMeasurer,
        style = TextStyle(
            fontSize = currentFontSize,
            fontFamily = fontFamily,
            color = Color.Black,
            textAlign = TextAlign.Center,
            fontWeight = FontWeight.Bold,
        ),
        text = text.uppercase(),
        topLeft = Offset(textX, textY),
        constraints = Constraints(maxWidth = availableWidth.toInt())
    )
}

关键改动说明

  • 添加宽度约束测量:通过Constraints(maxWidth = availableWidth.toInt())让TextMeasurer计算文本在指定宽度内换行后的实际高度,不再依赖单行宽度计算缩放因子。
  • 动态调整字号:先尝试默认字号,若换行后高度超过矩形可用空间,逐步缩小字号直到适配或达到最小字号,避免过度缩小。
  • 文本真正居中:计算文本的水平和垂直偏移量,结合基线位置确保文本在矩形内完全居中,而非从左上角开始绘制。
  • 添加内边距:给文本和矩形边框之间留一定间距,避免文本紧贴边框,提升视觉效果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 06:15:18