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
相关产品推荐
相关产品推荐

