前言
上一节,学会了Paint,Canvas的基本用法后,这一节,学习Paint的高级用法。还没看过上一节的请点击这里:Android_2D绘图的学习Paint,Canvas(一)。
一,文字的绘制
在做UI的时候,常常会绘制文字,Canvas绘制文字时,主要考虑到字体的宽度和高度问题。字体的宽度比较好理解,这里我们主要考虑一下字体的高度。
先看一张图,网上搜的:
这里说明了在安卓中绘制字体时对于高度的划分:top,ascent,baseLine,descent,bottom.有点类似我们刚开始学英语的时候的练习本。字体的高度我们取得是ascent到descent的距离。经过我测试,系统自带的TextView中,绘制的背景高度为top到bottom的距离。字体的起始坐标点默认是baseLine中最左边的一个点,可以通过调用Paint.setTextAlign(Paint.Align align)方法设置中间还是最右边。
我们先来绘制一个正确的文字居中的一个效果:
代码:
private Paint mPaint;
private String mText = "Android Paint学习";
public PaintView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mPaint = new Paint();
mPaint.setColor(Color.BLACK);
mPaint.setTextSize(TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_SP, 20, getResources()
.getDisplayMetrics()));
}
public PaintView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
// TODO Auto-generated constructor stub
}
public PaintView(Context context) {
this(context, null);
// TODO Auto-generated constructor stub
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//得到文字宽度
int textWidth = (int) mPaint.measureText(mText);
//得到文字高度
int textHeight = (int) (mPaint.descent() - mPaint.ascent());
// 设置View的高度和宽度为字体的高度和宽度
widthMeasureSpec = MeasureSpec.makeMeasureSpec(textWidth,
MeasureSpec.EXACTLY);
heightMeasureSpec = MeasureSpec.makeMeasureSpec(textHeight,
MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onDraw(Canvas canvas) {
//这里减去了一个descent主要是画笔画文字的基准线为baseLine,如果不剪,就会出现底部有一部分看不到的情况
canvas.drawText(mText, 0, getHeight() - mPaint.descent(), mPaint);
}
明显可以看出系统的TextView要高一点。注意top和ascent的值都是负值,所以在获取高度时,是减去ascent。如果要像TextView一样的高度的方法代码:
FontMetrics fm = mPaint.getFontMetrics();
int textHeight = (int) (fm.descent - fm.top+2);
因为Paint没有top()这个方法所以我们用FontMetrics中的top属性。
这里参考了一篇博文:Android字体高度的研究讲的很详细的。
二,Paint.Cap
The Cap specifies the treatment for the beginning and ending of stroked lines and paths. The default is BUTT.
cap是帽子,覆盖的意思,在画笔中,就是指定边缘点(画笔第一点,和画笔最后一点)的样式。
一共有3种样式:BUTT,ROUND,SQUARE.
我都以画一段圆弧来说明,效果:
从左至右分别是:SQUARE,ROUND,BUTT一看图,就了然了。
代码:
mPaint.setColor(Color.RED);
mPaint.setStrokeWidth(2);
canvas.drawLine(0, 50, getWidth(), 50, mPaint);
mPaint.setStrokeWidth(30);
mPaint.setStyle(Style.STROKE);
mPaint.setAntiAlias(true);
mPaint.setColor(Color.BLACK);
mPaint.setStrokeCap(Cap.BUTT);
canvas.drawArc(new RectF(-getWidth() + 150, -getHeight() + 150,
getWidth() - 50, getHeight() - 50), 0, 50, false, mPaint);
mPaint.setStrokeCap(Cap.ROUND);
canvas.drawArc(new RectF(-getWidth() + 100, -getHeight() + 150,
getWidth() - 100, getHeight() - 50), 0, 50, false, mPaint);
mPaint.setStrokeCap(Cap.SQUARE);
canvas.drawArc(new RectF(-getWidth() + 50, -getHeight() + 150,
getWidth() - 150, getHeight() - 50), 0, 50, false, mPaint);
三,Paint.join
The Join specifies the treatment where lines and curve segments join on a stroked path. The default is MITER.
摘自官方文档,就是说路径在转弯的时候指定其样式。
一共有3种样式:MITER,ROUND,BEVEL。
效果:
从左至右分别是:MITER,ROUND,BEVEL。
代码:
mPaint.setStrokeWidth(40);
mPaint.setStyle(Style.STROKE);
mPaint.setStrokeJoin(Join.MITER);
Path path = new Path();
path.moveTo(0, 30);
path.lineTo(100, 30);
path.lineTo(100, 100);
canvas.drawPath(path, mPaint);
mPaint.setStrokeJoin(Join.ROUND);
Path path1 = new Path();
path1.moveTo(200, 30);
path1.lineTo(300, 30);
path1.lineTo(300, 100);
canvas.drawPath(path1, mPaint);
mPaint.setStrokeJoin(Join.BEVEL);
Path path2 = new Path();
path2.moveTo(400, 30);
path2.lineTo(500, 30);
path2.lineTo(500, 100);
canvas.drawPath(path2, mPaint);
四,Paint.FontMetrics
调用Paint.getFontMetrics()会返回一个FontMetrics对象,调用前记得先设置字体大小,该对象有5个属性,分别是:top,ascent,descent,bottom,leading(行间距).注意前2个的值为负。