您的位置:首页 > 移动开发 > Android开发

android学习16#--学习canvas.drawText

2016-07-15 15:01 441 查看
本来这篇文章是要写写我在设计高级跑马灯程序的心得的,但是编写过程中花了近一天多的时间搞明白canvas.drawText中的第三个参数[float y]代表的真实含义。学习本文应该能帮助大家掌握FontMetrics类和Rect类成员变量值具体含义。

drawText引出问题

先来看看api中是如何定义drawText的参数。

/**
* Draw the text, with origin at (x,y), using the specified paint. The
* origin is interpreted based on the Align setting in the paint.
*
* @param text  The text to be drawn
* @param x     The x-coordinate of the origin of the text being drawn
* @param y     The y-coordinate of the baseline of the text being drawn
* @param paint The paint used for the text (e.g. color, size, style)
*/
public void drawText(@NonNull String text, float x, float y, @NonNull Paint paint) {
native_drawText(mNativeCanvasWrapper, text, 0, text.length(), x, y, paint.mBidiFlags,
paint.getNativeInstance(), paint.mNativeTypeface);
}


简单解释下各参数:

@param text:要显示的文本内容,这个不难理解。

@param x:文本相对屏幕原点x方向距离,没有更深的含义,也比较好理解

@param y:文本的baseline相对屏幕原点y方向距离。好,问题来了,baseline是个什么鬼东东

@param paint:画笔

baseline的来龙去脉

先看看baseline在文字区域的位置。通过一个实例来分析,这里只贴主要的code。

@Override
protected void onDraw(Canvas canvas) {
//super.onDraw(canvas);

mRect = new Rect();
mPaint = new Paint();
mPaint.setTextSize(64);
mPaint.setColor(Color.RED);

Paint.FontMetricsInt fontMetrics = mPaint.getFontMetricsInt();
mPaint.getTextBounds(textStr, 0, textStr.length(), mRect);

int w = mRect.width();
int h = mRect.height();

mRect = new Rect(mRectLeft, mRectTop, mRectLeft+w, mRectTop+(-fontMetrics.top)+fontMetrics.bottom);

canvas.drawRect(mRect, mPaint);

mBaseLine = (mRect.bottom+mRect.top)/2
- (fontMetrics.bottom+fontMetrics.top)/2;

mBaseLine = -fontMetrics.top;

/*其中y == mBaseLine的值*/
mPaint.setColor(Color.WHITE);
canvas.drawText(textStr, mRectLeft, mBaseLine, mPaint);

mPaint.setColor(Color.BLUE);
mPaint.setStrokeWidth(3);
/*将mBaseLine所在的位置画出来*/
canvas.drawLine(mRectLeft, mBaseLine, mRectLeft+w, mBaseLine, mPaint);
}


效果图:



分析

从上图可以看出来,baseline并不是文字区域的底部,但是这根线的位置相信大家都熟悉,除非你没有学过英语。

FontMetrics

FontMetrics是Paint静态内部类,主要定义了Paint绘制文本时的关键坐标。API中这么描述:

Class that describes the various metrics for a font at a given text size. Remember, Y values increase going down, so those values will be positive, and values that measure distances going up will be negative. This class is returned by getFontMetrics().


主要意思:根据设定的fontsize来获得字体的各种变量值。通过getFontMetrics()方法来获取。

FontMetrics类含有5个成员变量:

public static class FontMetrics {
/**
* The maximum distance above the baseline for the tallest glyph in
* the font at a given text size.
*/
public float   top;
/**
* The recommended distance above the baseline for singled spaced text.
*/
public float   ascent;
/**
* The recommended distance below the baseline for singled spaced text.
*/
public float   descent;
/**
* The maximum distance below the baseline for the lowest glyph in
* the font at a given text size.
*/
public float   bottom;
/**
* The recommended additional space to add between lines of text.
*/
public float   leading;
}


很明显所有的值都是基于baseline来算的。这里我主要关注top这个值的定义。

top:api的注释翻译过来意思是字体可绘制区域最高位置与baseline的距离。但是它是个负数,所以-top就是我们的baseline坐标值。

ascent:字体下单个字符最高位置与baseline的距离

descent:字体下单个字符最低位置与baseline的距离,与ascent镜像对应

bottom:字体可绘制区域最低位置与baseline的距离。

leading:字面翻译是文本线额外的空间。一般都为0,不知道有何用处。

Rect

Rect类表示的一块矩形区域。Paint类中getTextBounds()方法可以获取对应font size下文本所占用矩形区域。记住这个矩形区域的坐标值也是相对baseline来计算的。

Rect类成员变量有4个,分别是left、top、right、bottom。由于文本的rect区域是相对baseline来计算的,因此真实的top跟bottom都要加上baseline的值。

借助一个实例来理解FontMetrics和Rect

主要源码:

@Override
protected void onDraw(Canvas canvas) {
//super.onDraw(canvas);

mRect = new Rect();
mPaint = new Paint();
mPaint.getTextBounds(textStr, 0, 1, mRect);
mPaint.setTextSize(textSize);
mPaint.setColor(0xffF4A460);

Paint.FontMetricsInt fontMetrics = mPaint.getFontMetricsInt();
mPaint.getTextBounds(textStr, 0, textStr.length(), mRect);

int w = mRect.width();
int h = mRect.height();

/*给fontMetrics区域填充0xffF4A460色*/
mRect = new Rect(mRectLeft, mRectTop, mRectLeft+w, mRectTop+(-fontMetrics.top)+fontMetrics.bottom);
canvas.drawRect(mRect, mPaint);

/*计算baseline,其中mRectTop是控件顶部到父view的距离*/
mBaseLine = -fontMetrics.top + mRectTop;

/*其中y == mBaseLine的值*/
mPaint.setColor(Color.WHITE);
canvas.drawText(textStr, mRectLeft, mBaseLine, mPaint);

mPaint.setColor(Color.BLUE);
mPaint.setStrokeWidth(4);
/*蓝色线:将mBaseLine所在的位置画出来*/
canvas.drawLine(mRectLeft, mBaseLine, mRectLeft+w, mBaseLine, mPaint);

mPaint.setColor(Color.GREEN);
/*绿色线:将文字区域的bottom所在的位置画出来*/
canvas.drawLine(mRectLeft, mBaseLine+fontMetrics.bottom, mRectLeft+2*w
, mBaseLine+fontMetrics.bottom, mPaint);

mPaint.setColor(Color.RED);
/*红色线:将文字区域的top所在的位置画出来*/
canvas.drawLine(mRectLeft, mBaseLine+fontMetrics.top, mRectLeft+2*w
, mBaseLine+fontMetrics.top, mPaint);

mPaint.setColor(Color.GRAY);
/*灰色线:将文字区域的ascent所在的位置画出来*/
canvas.drawLine(mRectLeft, mBaseLine+fontMetrics.ascent, mRectLeft+w+50
, mBaseLine+fontMetrics.ascent, mPaint);

mPaint.setColor(Color.WHITE);
/*白色线:将文字区域的descent所在的位置画出来*/
canvas.drawLine(mRectLeft, mBaseLine+fontMetrics.descent, mRectLeft+w+50
, mBaseLine+fontMetrics.descent, mPaint);

mPaint.setColor(Color.YELLOW);
/*黄色线:将文字区域的leading所在的位置画出来*/
canvas.drawLine(mRectLeft, mBaseLine+fontMetrics.leading, mRectLeft+w/2
, mBaseLine+fontMetrics.leading, mPaint);

/*将“测”字的rect用矩形绘出来*/
mPaint.setColor(Color.BLACK);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.getTextBounds(textStr, 0, 1, mRect);
mRect.top+=mBaseLine;
mRect.bottom+=mBaseLine;
canvas.drawRect(mRect, mPaint);

/*将“测试:12hg”字的rect用矩形绘出来*/
mPaint.setColor(Color.BLACK);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.getTextBounds(textStr, 0, 7, mRect);
mRect.top+=mBaseLine;
mRect.bottom+=mBaseLine;
canvas.drawRect(mRect, mPaint);
}


效果图:



FontMetrics:

1. 浅黄色区域就是文字的FontMetrics区域,可以看出来文字实在此区域垂直居中绘制

2. 红色线:为FontMetrics的top

3. 灰色线:为FontMetrics的ascent

4. 黄色线:为FontMetrics的leading

5. 蓝色线:为baseline线

6. 白色线:为FontMetrics的descent

7. 绿色线:为FontMetrics的bottom

Rect:

1. 第一个小黑矩形为“测”字的rect区域

2. 第二个长黑矩形为“测试:12hg”字的rect区域

总结

只要彻底弄明白baseline才能轻松掌握drawText接口,才不至于开发的时候总是搞不明白绘制的文字要么偏上要么偏下。

参考

/article/1645248.html

/content/2870348.html

/article/2174639.html

/article/9749301.html

/article/3746805.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: