自定义View文字居中api小研究

一个关于自定义View中文字居中的一点点小总结,开发中曾遇到在自定义View中去绘制文字,要求文字居中显示,这种需求相信很多人都有遇到过,实现上没什么难度就是确定好baseline的坐标点即可。baseline的y坐标点如何确定自己理解的话应该是有两种方式,这里就大致说下这两种方式的区别。开始之前先说一下baseline。

baseLine

baseLine的作用有了解过文字绘制的应该都知道它的作用,多说无益直接使用一张网上的图就能明白
《自定义View文字居中api小研究》 5017748-0fd8d5f2a4e531a0.png

图中只需要去关心什么是baseline即可,其他都可以去忽略,相信看完后都能知道baseline的作用,但是实际上android的真正baseline和网上大多数的这种示意图有一点点的出入,图中可以发现M i A f这些字符的最底部都是正好在baseline之上,自己实测后发现并非如此会有一点点的偏差,测试关键代码如下

canvas.drawText(str, 0, getHeight() / 2, paint);
canvas.drawLine(0, getHeight() / 2, getWidth(), getHeight() / 2,paint);

得到的运行结果如图所示

《自定义View文字居中api小研究》 QQ截图20181203124756.png

,其中baseline就是那条黑色横线,可以发现字符并非真正意义上居于baseline之上,会有一点点的偏差,这点偏差对于文字居中绘制实际上并没有多大影响,单独拿出来讲下只是希望大家知道网上很多关于android baseline的图解可能存在一点问题。

利用TextBounds实现文字居中

代码就一句,paint.getTextBounds(str, 0, str.length(), rect); str就是需要绘制的文本内容,getTextBounds会将得到的结果保存在rect里面,
涉及到文字居中的两个变量是top和bottom,为了使文字居中显示,baseline的计算公式为

baseLine=getHeight() / 2 - (rect.top + rect.bottom) / 2

android 文字坐标系中,在baseline之上的为负数,baseline之下的为正数,所以可以发现rect.top 是一个负数,rect.bottom是一个正数,-(rect.top + rect.bottom) / 2的结果就是实际baseline需要偏移的量,最终将这个结果和getHeight() / 2相加得到真正baseline的位置。

使用getTextBounds去实现文字的居中,可以做到绝对居中,如何理解这句话意思呢,两行代码就能明白

        paint.getTextBounds(“aaaa”, 0, 4, rect1);
        paint.getTextBounds(“abcd”, 0, 4, rect2);

rect1和rect2中top和bottom的值都是不一样的,每次getTextBounds得到的结果都是会根据不同文字而改变,也就是说
baseLine=getHeight() / 2 – (rect.top + rect.bottom) / 2得到的结果也会有差异,通过两种图对比

《自定义View文字居中api小研究》 QQ截图20181203131733.png

《自定义View文字居中api小研究》 QQ截图20181203132034.png

可以看出当从aaaa变成abcd时字符a会有一个小的偏移量,如果自定义view中涉及到动态改变文字,使用这种居中方式最大的一个缺点就是可能会产生忽上忽下的字符跳动。当然如果不涉及到动态改变文字其实这种居中方式更可行,因为它可以做到几乎的绝对居中效果,不能完全做到居中的原因我在最开始已经说过了,android的文字实际上并非完全在baseline之上绘制的,不过这点小问题影响不大。

利用FontMetrics实现居中

接下来要说的文字居中对齐实际并非真正意义上的居中,但是它的一个优点就是可以做到不受文字动态改变而影响。Paint类中还有一个api叫做getFontMetrics,关于里面几个字段的意义相信大家也都知道具体含义,一图来说明

《自定义View文字居中api小研究》 QQ截图20181203133257.png 图是直接从
https://blog.csdn.net/u012551350/article/details/51361778拿过来的不想再画了,对照着看下就能知道FontMetrics中各个字段的含义了,所以baseLine的计算公式就能得到

baseLine=getHeight() / 2 - (fontMetrics.top + fontMetrics.bottom) / 2

利用getFontMetrics绘制文字居中效果最终得到的效果图如下
《自定义View文字居中api小研究》 QQ截图20181203141334.png

嗯你没看错,看起来根本没有居中对齐,但是使用getFontMetrics得到的效果就是这样的,如果换成其他字符你就能看出差异
《自定义View文字居中api小研究》 QQ截图20181203134118.png

造成上述的原因就是fontMetrics的top和bottom值只和字体大小有关和具体的文字是没有关系的,这和getTextBounds方法有很大的不同。

上述两种不同居中方式已经说得比较明白了,具体在实际需求中使用哪种需要自己灵活来处理。特此记录下自己的这点小研究。

    原文作者:mandypig
    原文地址: https://www.jianshu.com/p/6bcc06251550
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞