继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

Android文字基线(Baseline)算法

nickcau
关注TA
已关注
手记 114
粉丝 6509
获赞 303

引言

Baseline是文字绘制时所参照的基准线只有先确定了Baseline的位置我们才能准确的将文字绘制在我们想要的位置上。Baseline的概念在我们使用TextView等系统控件直接设置文字内容时是用不到的但是如果我们想要在Canvas画布上面绘制文字时Baseline的概念就必不可少了。 

我们先了解一下Android中Canvas画布绘制文字的方法如下图 

Androidç»å¶æå­æ¹æ³åæ°.png

参数示意


text文字内容

x文字从画布上开始绘制的x坐标Canvas是一个原点在左上角的平面坐标系

yBaseline所在的y坐标不少人已开始以为y是绘制文字区域的底部坐标其实是不正确的这是两个概念

paint画笔设置的文字的大小颜色等属性 

了解了文字绘制的方法我们现在就了解一下这个参数yBaseline的计算方法。

Baseline的概念

æå­åºåç®å计ç®å¾.png

我们看到如果文字的上方有一些特殊的符号比如上图中的~或者是我们汉语拼音中的声调时文字区域又会多出一部分Leading。 
因此完整的公式应该是文字的高度=Descent+Ascent+Leading。

其中leading=0所以我们在文字绘制时不需要考虑Leading图中的数值都是距离Baseline的距离在Baseline上方为负值下方为正值。

Baseline位置y轴坐标的计算

为了方便我们对计算过程进行理解我画了一幅帮助图如下

æå­åºçº¿è®¡ç®å¾.png

假设我们是在画布Canvas的顶部绘制一行文字规定一行文字的高度是y文字区域的高度是HeightTOP和BOTTOM之间TOP到0和BOTTOM到y的距离相等这样文字才看起来是居中。因此0到y和TOP到BOTTOM的中线是重合的y轴坐标都是y/2。 

我们要绘制一行文字时设计必然会告诉我们0到y的距离所以中线的位置也是固定的y/2那么我们设置了Paint的文字大小后Ascent和Descent又能直接得到就可以算出中线到基线的距离公式如下 

基线到中线的距离=(Descent+Ascent)/2-Descent = Ascent-Descent)/2

注意实际获取到的Ascent是负数。公式推导过程如下 

中线到BOTTOM的距离是(Descent+Ascent)/2这个距离又等于Descent+中线到基线的距离即(Descent+Ascent)/2=基线到中线的距离+Descent。 

有了基线到中线的距离我们只要知道任何一行文字中线的位置就可以马上得到基线的位置从而得到Canvas的drawText方法中参数y的值。

我们看这个图baseLine可以这样获取如果我们知道中线的高度就是height/2,那么加上Ascent-Descent)/2就是baseLine的位置这个都是在textView的坐标系里

float textBaseY = height/2+(Math.abs(paint.ascent())-paint.descent())/2;

如果以top和bottom来计算BaseLine:

https://img.mukewang.com/5c58d81c0001603319280832.jpg

可以总结:

字内容的坐标系和TextView组件的坐标系是不一样的

字内容是以其父容器的baseline为原点的。

如果我们想自己实现一个TextView,并且实现字内容能够垂直居中我们在画布中绘制文本的时候会调用Canvas.drawText(String text, float x, float y, Paint paint)这个方法其中y的坐标就是上图中baseline的y坐标所以如果我们只是简单地把drawText方法中的y设置为控件高度的1/2是不准确的。实际上: 

https://img1.mukewang.com/5c58d85200013cab18961000.jpg

Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();//获得画笔的FontMetrics用来计算baseLine。因为drawText的y坐标代表的是绘制的文字的baseLine的位置
int baseline = (int) ((Height - fontMetrics.bottom - fontMetrics.top) / 2);//计算出在每格index区域竖直居中的baseLine值


参考https://blog.csdn.net/hailuoli/article/details/78558594 

https://blog.csdn.net/xude1985/article/details/51532949 

打开App,阅读手记
1人推荐
发表评论
随时随地看视频慕课网APP

热门评论

/**
 * The recommended additional space to add between lines of text.
 */
public int   leading;

leading说的应该是行间距,不是音标高度

查看全部评论