android: Canvas drawText()文字居中

嫌麻烦可以直接看结论:

文本居中的公式:

float baseLineY = centerY + (Math.abs(fontMetrics.top) + Math.abs(fontMetrics.bottom)) /2 - fontMetrics.bottom

也可以简化成:

float baselineY = centerY + (fontMetrics.bottom - fontMetrics.top)/2 - FontMetrics.bottom;

PS: 

1. centerY就是文本所在父View的中点的Y坐标。比如文本想要在一个高度为40dip的View中垂直居中,那centerY就是20dip; 
2.  FontMetrics.bottom  和   FontMetrics.top 是怎么拿到的?在绘制文本之前肯定先要给这段文本设置字体或大小这样的代码,比如:

mPaint.setTextSize();
在调用这段代码之后就可以拿到  FontMetrics ,通过:

Paint.FontMetrics fontMetrics = mTextPaint.getFontMetrics();

然后就可以通过上面的公式, 计算drawText()函数中传入的Y值了。

-----------------------------------------------------------------------------------------  华丽丽的分割线 --------------------------------------------------------------------------------------------------------

这里面有个坑,就是drawText()方法里传入的x, y坐标不是文字中心点的坐标, 而是基线的坐标!为什么是基线的坐标,是为了适配不同的文字,使不同文字放在一起时看起来更美观协调,可以用下图很直观的解释这种方式:

如何理解基线,可以参考下面这幅图:

 

像图上这样安卓的文字绘制是相对于基线绘制的,也就是图中的红线,而top+bottom的长度就等于字体高度.即等于|top|+|bottom|绝对值

实际绘制的时候取决于基线上一个点来绘制文字,而这个点有三种分别对应为left,center,right如下图:

而drawText()方法中x,y坐标所指的点就是上图基线上三个点中的一个,具体是哪一个根据paint的setTextAlign()方法设置,默认为left

示例代码如下

        Rect rect = new Rect(100,100,500,500);//画一个矩形
        Paint rectPaint = new Paint();
        rectPaint.setColor(Color.BLUE);
        rectPaint.setStyle(Paint.Style.FILL);
        canvas.drawRect(rect, rectPaint);
 
        Paint textPaint = new Paint();
        textPaint.setColor(Color.WHITE);
        textPaint.setTextSize(50);
        textPaint.setStyle(Paint.Style.FILL);
        //该方法即为设置基线上那个点究竟是left,center,还是right  这里我设置为center
        textPaint.setTextAlign(Paint.Align.CENTER);
 
        Paint.FontMetrics fontMetrics = textPaint.getFontMetrics();
        float top = fontMetrics.top;//为基线到字体上边框的距离,即上图中的top
        float bottom = fontMetrics.bottom;//为基线到字体下边框的距离,即上图中的bottom
 
        int baseLineY = (int) (rect.centerY() - top/2 - bottom/2);//基线中间点的y轴计算公式
 
        canvas.drawText("你好世界",rect.centerX(),baseLineY,textPaint);    

这里有点要注意textPaint.getFontMetrics()这个方法一定要在设置字体大小或者样式等等一系列会影响字体的方法后在调用,不然获取到的top和bottom值不准.

效果如下:

 

 

正好是在中间的,即证明等式是没有问题的,再来分析这个等式是如何计算的

之所以drawText()方法中x,y指的是基线中间的那个点,是因为setTextAlign(Paint.Align.Center)

那么要想在正中间显示文字,x只要为矩形的中点x坐标即可 x = rect.centerX()

要计算的就是基线中间图上红色点的y坐标了,看图可以发现红色点的y为矩形中点黑色点的y坐标+图中黑色点和红色点之间的距离

矩形y坐标为 rect.centerY()

黑色点和红色点之间的距离为相对于基线的(top+bottom)/2 - bottom

而 top是相对于基线的所以为负数,所以公式为 (-top+bottom)/2 - bottom简化下为-top/2 - bottom/2

所以最后计算为rect.centerY - top/2 - bottom/2 - bottom

计算方式就是用: 文本的总高度的一半减去基线到bottom线的距离,算出基线到中点之间的距离,然后再用中间的Y坐标加上这个距离,就是文本的基线位置。

 

 参考链接:

1. android canvas drawText()文字居中

2. 自定义控件之绘图篇( 五):drawText()详解

3. 迷之 paint.getTextBounds()

 

posted @ 2020-09-22 11:38  夜行过客  阅读(2310)  评论(0编辑  收藏  举报