Compose Canvas调用drawText文本超出屏幕,未遵循宽度限制
Compose Canvas绘制文本超出设置宽度的问题排查
我用以下代码在Compose Canvas上绘制文本,但截图显示文本超出屏幕范围,没有遵循给Canvas设置的500dp宽度参数。旧版Android Canvas不会有这个问题,这是Compose的Bug吗?
Box( modifier = Modifier .fillMaxWidth() ) { Canvas( modifier = Modifier.width(500.dp), onDraw = { drawIntoCanvas { it.nativeCanvas.drawText( text, 0f, 120.dp.toPx(), textPaintStroke(context = context) ) it.nativeCanvas.drawText( text, 0f, 120.dp.toPx(), textPaint(context = context) ) } } ) } fun textPaintStroke( context: Context ): NativePaint { val customTypeface = ResourcesCompat.getFont(context, R.font.baloo2_semi_bold) return Paint().asFrameworkPaint().apply { isAntiAlias = true style = android.graphics.Paint.Style.STROKE textSize = 64f color = android.graphics.Color.BLACK strokeWidth = 12f strokeMiter= 10f strokeJoin = android.graphics.Paint.Join.ROUND typeface = customTypeface } } fun textPaint( context: Context ): NativePaint { val customTypeface = ResourcesCompat.getFont(context, R.font.baloo2_semi_bold) return Paint().asFrameworkPaint().apply { isAntiAlias = true style = android.graphics.Paint.Style.FILL textSize = 64f color = android.graphics.Color.WHITE typeface = customTypeface } }

问题原因
这不是Compose的Bug,核心原因是你直接调用nativeCanvas.drawText绕过了Compose Canvas的布局约束:
- Compose Canvas的
modifier.width(500.dp)仅用于确定自身的布局尺寸,不会自动限制原生Canvas的绘制范围。 - 原生Canvas的绘制空间默认对应整个父布局的画布区域,不会自动裁剪超出modifier设定区域的内容,旧版Android自定义View的
onDraw默认也不会自动裁剪,除非手动设置裁剪规则。
解决方法
方法1:手动添加裁剪区域
在drawIntoCanvas外层通过clipRect限制绘制范围,使用size.width获取Canvas设定宽度的像素值:
Canvas( modifier = Modifier.width(500.dp), onDraw = { // 裁剪到Canvas的实际布局尺寸 clipRect(0f, 0f, size.width, size.height) { drawIntoCanvas { it.nativeCanvas.drawText( text, 0f, 120.dp.toPx(), textPaintStroke(context = context) ) it.nativeCanvas.drawText( text, 0f, 120.dp.toPx(), textPaint(context = context) ) } } } )
方法2:使用Compose原生drawText API
改用Compose提供的drawText和TextMeasurer,更符合Compose设计范式,自动适配布局约束:
val textMeasurer = rememberTextMeasurer() Canvas(modifier = Modifier.width(500.dp)) { // 绘制描边文本 drawText( textMeasurer = textMeasurer, text = text, style = TextStyle( fontSize = 64.sp, fontFamily = FontFamily(Font(R.font.baloo2_semi_bold)), color = Color.Black, drawStyle = Stroke(width = 12f, miter = 10f, join = StrokeJoin.Round) ), topLeft = Offset(0f, 120.dp.toPx()) ) // 绘制填充文本 drawText( textMeasurer = textMeasurer, text = text, style = TextStyle( fontSize = 64.sp, fontFamily = FontFamily(Font(R.font.baloo2_semi_bold)), color = Color.White ), topLeft = Offset(0f, 120.dp.toPx()) ) }
如果需要文本自动换行或严格限制宽度,可以配合Constraints参数给TextMeasurer.measure设置最大宽度。
内容的提问来源于stack exchange,提问作者alfietap
相关产品推荐
相关产品推荐

