1.文字测量标准
关于字体baseline以及相关属性有一个类,里面包含了top,ascent,baseline,descent,bottom。在Paint源码API中的解释如下图所示:
上图API里面的描述可能不是很容易理解,更加直观的以下图所示:
2.计算文字绘制位置
掌握了文字的测量标准,那么如何正确地绘制位置就比较容易了。举个例子,比如要在圆形的中间位置绘制文字内容。先绘制一个圆形,绘制代码如下:
绘制结果如下图所示:
现在想在上图圆的中心位置绘制文字,比如绘制文字hgaajkq,调用绘制代码如下图所示:
上图所示的文字内容竖直没有居中,这是为什么呢?结合API drawText(@NonNull String text, float x, float y, @NonNull Paint paint)了解到参数y就是文字的baseline,整个文字绘制内容大部分都会在baseline的上方,为了更加直观的看效果,我把baseline的位置用红线画出来,如下图所示:
要想文字内容中心位置居中,那么就要将文字的中心位置偏移到圆的中心,也就是实际上传入的baseline位置要去除一个偏移offset(上图所示是要将文字往下移)。依据第一节中文字测量模式的理解,文字的中心位置为(fontMetrics.ascend + fontMetrics.descend) / 2(这个结果是基于baseline的)。所以要想将文字竖直中心移动到实际的中心位置才算竖直方向的完全居中效果。如下图所示(蓝色绘制是移动的结果):
上图中红色线是绘制黑色时的baseline,将黑色状态时文字中心移到红线的位置,就是将文字绘制居中。所以将绘制调整如下图所示,完成绘制文字内容真正意义上的居中。
除了(fontMetrics.descent +fontMetrics.ascent) /2这种方法获取文字的中心偏移,还有一种方法。我们知道上面这个方法文字中不会随着文字内容而改变,它是一种字体相关的测量模式。比如我将绘制字体变为"aaaaaa",绘制的视觉效果如下图所示:
去除之前实验过程,看最终结果居中效果图:
从图中来看当前文字内容有点偏下,这是绘制位置错误了?其实并不是,主要跟字体有关,(fontMetrics.descent +fontMetrics.ascent) /2这种中心偏移方法,依据的是字体固有属性,比如像英文字体它的fontMetrics这个里面top,ascent,baseline,descent,bottom是确定的,不会随着不同的英文字母内容发生变化的。所以第一种居中文字绘制方式适合连续编辑的情况,这样不管当前绘制什么内容,文字的竖直中心不会发生变化,也就是不会出现上下跳动。
那如果想要根据文字绘制内容获取几何层面的中心点,那得用另外一套测量方法计算。如下图所示:
从API源码获取到最小包裹当前文字内容的矩形,也就是跟字体本身关系不大,与具体的测量字体内容有关系。测试代码以及相应的结果如下图所示:
为了更加方便对比效果,将两种测量方式的绘制内容放一起,代码和效果如下图所示:
上图中灰色的是依赖字体测量方式的绘制结果,蓝色是依赖文字内容的测量方式的绘制结果。依赖文字内容的测量绘制方式适合文字内容固定的,不适合动态编辑的,因为内容在变的话,文字内容最小包裹矩形也是变化的,从而导致绘制连续编辑更改内容时是中心点可能上下跳动,间接产生不好的视觉体验和效果。
3.总结
文字绘制时测量竖直方向的位置偏移有两种方式:
1)与字体有关的测量方法,计算得到的文字竖直中心为(fontMetrics.ascent +fontMetrics.descent) /2
2)与文字内容有关的测量方法,计算得到的文字竖直中心为(textBounds.top +textBounds.bottom) /2
方法1)适用绘制时动态编辑文字内容的情况;方法2)使用绘制固定文字内容,某种意义上能更好的还原视觉效果。
网友评论