Android Canvas绘制文本时如何正确计算基线y以适配Paint.getTextBounds边界
正确计算基线坐标的方案
你出现截断的核心原因是使用了全局字体的FontMetrics.descent参数计算基线,该参数是字体所有字符的最大下行高度,和当前传入文本的实际边界不匹配。而Paint.getTextBounds()返回的Rect是针对你当前输入文本计算的实际渲染边界,直接用它的参数计算即可:Paint.getTextBounds()返回的Rect默认以基线为坐标原点:
rect.top:文本顶部相对基线的偏移(为负值,因为在基线上方)rect.bottom:文本底部相对基线的偏移(为正值,因为在基线下方)
要让文本刚好完整渲染在大小为rect.width() * rect.height()的Bitmap中,基线的y坐标直接取-rect.top即可,无需使用FontMetrics的全局参数。
修改后的核心绘制代码如下:
final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); final Rect rect = new Rect(); paint.getTextBounds(text, 0, text.length(), rect); final int width = rect.width(); final int height = rect.height(); Bitmap rendered = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); final Canvas gOfRendered = new Canvas(rendered); paint.setColor(Color.WHITE); // 核心修改:x偏移抵消rect.left的字体内边距,y坐标直接取-rect.top作为基线位置 gOfRendered.drawText( text, -rect.left, -rect.top, paint ); gOfRendered.drawColor(0x11ffffff); // 用于查看边界
这个方案对所有文本都生效,不管文本有没有下行字符(比如g、y这类带descent的字符,或者back这类无descent的字符),都不会出现截断问题,且文本会刚好填满getTextBounds返回的边界范围。
关于非基线参数的绘制接口
原生Android Canvas没有直接接收文本顶部坐标作为参数的单行文本绘制方法,你可以基于上面的基线计算逻辑封装一个工具方法,传入左上角坐标即可自动换算基线:
/** * 绘制单行文本,坐标为文本左上角位置 * @param canvas 画布 * @param text 待绘制文本 * @param left 文本左上角x坐标 * @param top 文本左上角y坐标 * @param paint 绘制用Paint */ public void drawTextByTopLeft(Canvas canvas, String text, float left, float top, Paint paint) { Rect rect = new Rect(); paint.getTextBounds(text, 0, text.length(), rect); canvas.drawText(text, left - rect.left, top - rect.top, paint); }
如果需要绘制多行文本,可以直接使用StaticLayout,它默认从传入的左上角坐标开始绘制,不需要手动计算基线。
内容的提问来源于stack exchange,提问作者hoshiKuzu
相关产品推荐
相关产品推荐

