android canvas.drawText在矩形内文字居中

参考自:https://blog.csdn.net/hursing/article/details/18703599

看博客的时候,有看到canvas.drawText()方法,但关于baseline这个点看了好久,也看不懂,于是乎,自己写了个demo,总算搞明白了
如若我们要在一个矩形内,绘制文本,需要文字竖直居中

/**
 * text 要绘制的文字
 * x 文字左端x坐标
 * y 文字基线baseline的y值 
 * paint 画笔
*/
drawText(String text, float x, float y, @NonNull Paint paint)

文字左端的x坐标不用解释,但文字基线baseline的y值是什么呢?
管它是什么,画出来再猜

Rect rect = new Rect(50, 50, 1000, 200);
mPaint.setColor(Color.CYAN);
canvas.drawRect(rect, mPaint);
mPaint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 16, mContext.getResources().getDisplayMetrics()));
mPaint.setColor(Color.BLACK);
canvas.drawText(str, rect.left, rect.bottom, mPaint);

这里写图片描述
如上图,即为矩形的底边为baseline的效果,其实类似于英文四线作业本的第三根线
那么,我们想把文字居中就要很准确的计算出baseline的y坐标
计算之前我们要再来认识另一个类,FontMetrics
还是先画为敬

int x = 50;
int y = 200;
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(Color.BLACK);
canvas.drawText(str, x, y, mPaint);
Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();
//绘制baseline
mPaint.setColor(Color.RED);
canvas.drawLine(50, 200, 1000, 200, mPaint);
canvas.translate(x, y);
//画fontMetrics.top位置
mPaint.setColor(Color.YELLOW);
canvas.drawLine(0, fontMetrics.top, 1000, fontMetrics.top, mPaint);
//画fontMetrics.bottom位置
mPaint.setColor(Color.MAGENTA);
canvas.drawLine(0, fontMetrics.bottom, 1000, fontMetrics.bottom, mPaint);

看下效果吧:
这里写图片描述
可以看到,黄线为fontmetrics.top,紫线为fontmetrics.bottom,文字在二者其中并且居中
顺便打印出fontmetrics.top fontmetrics.bottom的值如下:

*******************fontMetrics.top******************-76.04297
*******************fontMetrics.bottom******************19.511719

看到fontMetrics.top的值为负数
FontMetrics是描述给定文本字体的各种属性的类,我自己总结的就是包含了字体绘制边界
fontmetrics.top 给定字体大小的文本高于基准线的最大距离
同样的,fontmetrics.bottom 给定字体大小的文本低于基准线的最大距离
其实,根据上图已经可以看的很清楚了,我解释的可能也不够准确,已经很努力的用我的四级解释了
重点是基线baseline的y坐标为0,我意识到这点的时候,才把博主的博客看懂
回到原来的问题,我们要在给定矩形内绘制文字
baseline = rect.centerY() - (fontmetrics.bottom - fontmetrics.top)/2 - fontmetrics.top
baseline = 矩形的数值方向中心线y值 - 字体可绘制边界竖直方向的一半 + 字体可绘制边界的竖直方向顶部到基线的距离即fontmetrics.top
参照下图更好理解:
这里写图片描述

Rect rect = new Rect(50, 50, 1000, 200);
mPaint.setColor(Color.CYAN);
canvas.drawRect(rect, mPaint);
mPaint.setColor(Color.BLACK);
Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();
float bottomLineY = rect.centerY() - (fontMetrics.bottom - fontMetrics.top) / 2 - fontMetrics.top;
canvas.drawText(str, rect.left, bottomLineY, mPaint);

效果:居中,RNG冠军,nice!
这里写图片描述
另外,区分下,FontMetrics 和 getTextBounds 的区别

int x = 50;
int y = 200;
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(Color.BLACK);
canvas.drawText(str, x, y, mPaint);
Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();
Log.d("test", "*******************fontMetrics.top******************" + fontMetrics.top);
Log.d("test", "*******************fontMetrics.bottom******************" + fontMetrics.bottom);
//绘制baseline
mPaint.setColor(Color.RED);
canvas.drawLine(50, 200, 1000, 200, mPaint);
canvas.translate(x, y);
//画fontMetrics.top位置
mPaint.setColor(Color.YELLOW);
canvas.drawLine(0, fontMetrics.top, 1000, fontMetrics.top, mPaint);
//画fontMetrics.bottom位置
mPaint.setColor(Color.MAGENTA);
canvas.drawLine(0, fontMetrics.bottom, 1000, fontMetrics.bottom, mPaint);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(2);
//绘制汉字的字体的字体范围
Rect bounds1 = new Rect();
mPaint.setColor(Color.GREEN);
mPaint.getTextBounds(str, 0, 3, bounds1);
canvas.drawRect(bounds1, mPaint);
//绘制包含英文字体的字体范围
Rect bounds2 = new Rect();
mPaint.setColor(Color.BLUE);
mPaint.getTextBounds(str, 0, 7, bounds2);
canvas.drawRect(bounds2, mPaint);
//通过以上两个矩形对比可知,汉字的文字边框和英文的文字边框不同

老规矩,看图说话
这里写图片描述
我的总结是:
getTextBounds为当前文字实际绘制的最小矩形
FontMetrics为给定大小的文字可绘制边界(区分实际绘制,其实我也不是特别清楚,我觉得可能是因为存在下图的文字,所以可绘制边界要预留其额外的距离)
这里写图片描述
最近越来越觉得,自己要学的东西很多,要得到自己想要的,就要付出足够的努力,以前看别人博客经常会一言不合就被鸡汤,自己也炖一勺尝尝。。。加油吧!

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值