Android原生绘图(十四):drawText,getTextBounds,measureText,FontMetrics,基线

2,498 阅读2分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
本文已参与 「掘力星计划」 ,赢取创作大礼包,挑战创作激励金。

1.如何测量一段文本占用的长度和宽度

Paint类提供了测量宽高的方法:

getTextBounds(String text, int start, int end, Rect bounds)

返回一个包含所有字符,默认从(0,0)开始的最小矩形的矩形框。

measureText(String text, int start, int end):

返回text的宽度。

2.问题1 drawText函数指定的坐标(x,y)在哪个位置

很多人会以为指定的坐标都是在左上角,但绘制文本时指定的坐标却不是左上角。

drawText(@NonNull String text, float x, float y, @NonNull Paint paint)

利用Canvas.drawText绘制文本,并在(x,y)处绘制两个点

3.利用getTextBounds获取文本的宽高,measureText获取宽度

Rect rect1 = new Rect();
mPaint.getTextBounds(textStr,0,textStr.length(),rect1);

float textwidth =  mPaint.measureText(textStr);

利用measureText获取的宽度比getTextBounds获取的宽度稍大。

两种测量方式为什么不同:

measureText() 会在文本的左右两侧加上一些额外的宽度,这部分额外的宽度叫做 Glyph’s AdvanceX (具体应该是属于字型方面的范畴,我猜测这部分宽度是类似字间距之类的东西)

getTextBounds() 返回的则是当前文本所需要的最小宽度,也就是整个文本外切矩形的宽度,而且两个函数的精度也是不同的。

4.FontMetrics

FontMetrics中的每个字段都跟baseline有关

  • ascent是baseline之上至字符最高处的距离
  • descent是baseline之下至字符最低处的距离
  • leading是上一行字符的descent到下一行的ascent之间的距离,如果只有一行这个值为0,计算字体高度有时也需要加上这个数据。
  • top是最高字符到baseline的值,即ascent的最大值
  • bottom最下字符到baseline的值,即descent的最大值
Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();

可以看到baseline加上ascent之后,没有紧挨着字母的顶部,这时因为好多字在顶部还有很多符号.

getTextBounds获取的高度是不准确的,想要最大化获取字体的高度,应该使用descent的绝对值,加上ascent的绝对值。

5.获取text宽高

//获取宽度
public static float getTextWidth(String text, float textSize){
   Paint paint = new Paint();
   paint.setTextSize(textSize);
   return paint.measureText(text);
}

//获取高度
public static float getTextHeight(float textSize){
   Paint paint = new Paint();
   paint.setTextSize(textSize);
   FontMetrics fm = paint.getFontMetrics();   
       return fm.descent - fm.ascent;
}