只需要搞懂这两个方法。别看源码了,这两个方法调到最后都跑native那边去了。
Paint.getFontMetricsInt();
这个方法提供了文字排版的几个重要数据,top,ascent,descent,bottom,leading。最后一个leading不知道什么用,据说和额外边距有关,即上一行text的bottom距下一行text的top的距离,这里暂且用不到。
绘制文本时,调用canvas.drawText(String text, float x, float y, Paint paint);
值得注意的是,这里的x,y是文字的左下角的某个位置,具体如下图所示:
image.png
看到了吗,就那个小红点。
image.png
这里的y所在的线大家都叫它baseline。
现在关于Paint.getFontMetricsInt();所得到的这几条线全画出来是这个样子。多了个‘a’?嗯,我故意的。
image.png
这五条线依次是top,ascent,baseline,descent,bottom。
其中ascent和descent之间的区域是常见字符的范围,中文都是方块字,英文也还算规矩,一般不会超出这个区域。
这样文字所占的高度就可以拿到了:descent-ascent。也有人用bottom-top的。
Paint.getTextBounds(String text, int start, int end, Rect bounds);
刚开始拿到这个bounds,看到里面的数据也是一脸懵比。其实,它也以原点为基础,得到文字绝对大小的所在区域。
image.png
这两个方法研究透彻之后,要把一个文本绘制在一个区域的中间,要解决的就是一个数学问题了,即计算原点应该放到哪里。这里直接给出代码吧。
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int width = getMeasuredWidth();
int height = getMeasuredHeight();
drawText(canvas, width, height);
}
private void drawText(Canvas canvas, int width, int height) {
//获取起点x坐标
mPaint.getTextBounds(mText, 0, mText.length(), bounds);
float startX = (width - bounds.width()) / 2.0f;
//获取起点y坐标
Paint.FontMetricsInt fontMetrics = mPaint.getFontMetricsInt();
int baseline = (height - fontMetrics.descent - fontMetrics.ascent) / 2;
//绘制text
canvas.drawText(mText, startX, baseline, mPaint);
//绘制baseline
canvas.drawLine(0, baseline, width, baseline, mPaint);
//绘制top
float top = baseline + fontMetrics.top;
canvas.drawLine(0, top, width, top, mPaint);
//绘制ascent
float ascent = baseline + fontMetrics.ascent;
canvas.drawLine(0, ascent, width, ascent, mPaint);
//绘制descent
float descent = baseline + fontMetrics.descent;
canvas.drawLine(0, descent, width, descent, mPaint);
//绘制bottom
float bottom = baseline + fontMetrics.bottom;
canvas.drawLine(0, bottom, width, bottom, mPaint);
//绘制bounds区域
float rectLeft = startX + bounds.left;
float rectRight = startX + bounds.right;
float rectTop = baseline + bounds.top;
float rectBottom = baseline + bounds.bottom;
//top线
canvas.drawLine(rectLeft, rectTop, rectRight, rectTop, mPaint);
//left线
canvas.drawLine(rectLeft, rectTop, rectLeft, rectBottom, mPaint);
//right线
canvas.drawLine(rectRight, rectTop, rectRight, rectBottom, mPaint);
//bottom线
canvas.drawLine(rectLeft, rectBottom, rectRight, rectBottom, mPaint);
//绘制原点
mPaint.setStrokeWidth(3);
mPaint.setColor(Color.RED);
canvas.drawPoint(startX, baseline, mPaint);
}
网友评论