1、概念
画布,通过画笔绘制几何图形、文本、路径和位图等。
2、常用API
常用API分为绘制、变换、状态保存和恢复
2.1 绘制颜色
1. canvas.drawColor(Color.GREEN);
2.2 绘制集合图形
//绘制点
float[] pts = {200, 300, 200, 400, 200, 500};
canvas.drawPoints(pts, mPaint);
//绘制线
canvas.drawLine(200, 200, 200, 400, mPaint);
//绘制矩形
RectF rect = new RectF(100, 100, 400, 400);
canvas.drawRect(rect, mPaint);
//绘制圆角矩形
canvas.drawRoundRect(rect, 20, 20, mPaint);
//绘制圆
canvas.drawCircle(200, 200, 100, mPaint);
//绘制椭圆
canvas.drawOval(rect, mPaint);
//绘制圆弧
canvas.drawArc(rect, -180, 180, true, mPaint);
2.3 绘制文本
canvas.drawText(text, 50, 50, mPaint);
Path path = new Path();
path.addArc(100, 100, 300, 300, -180, 360);
canvas.drawPath(path, mPaint);
canvas.drawTextOnPath(text, path, 10, -10, mPaint);
2.4 绘制位图
canvas.drawBitmap(bitmap, 0, 0, mPaint);
Matrix matrix = new Matrix();
matrix.postRotate(45);
matrix.postTranslate(400, 0);
canvas.drawBitmap(bitmap, matrix, mPaint);
Rect src = new Rect(0, 0, 100, 200);
Rect dst = new Rect(600, 0, 700, 200);
canvas.drawBitmap(bitmap, src, dst, mPaint);
2.5 绘制路径
Path path = new Path();
path.moveTo(0,0);
path.lineTo(100,100);
path.lineTo(300,200);
canvas.drawPath(path, mPaint);
2.6 变换
//平移
canvas.translate(100, 100);
//旋转
canvas.rotate(45);
canvas.rotate(45, 100,100);
//缩放
canvas.scale(0.5f, 0.5f);
canvas.scale(0.5f, 0.5f, 100,100);
//错切
canvas.skew(0.1f, 0.5f);
2.6.1
rotate
可以叠加,而且这里实际上移动的是坐标,画布的位置并没有变,也就是说坐标原点变到了原来(100,100)的位置。
注意
:rotate(float degrees, float px, float py)
canvas.rotate(45, 100, 100);
源码:
/**
* Preconcat the current matrix with the specified rotation.
*
* @param degrees The amount to rotate, in degrees
* @param px The x-coord for the pivot point (unchanged by the rotation)
* @param py The y-coord for the pivot point (unchanged by the rotation)
*/
public final void rotate(float degrees, float px, float py) {
if (degrees == 0.0f) return;
translate(px, py);
rotate(degrees);
translate(-px, -py);
}
根据源码可以很明显的看到,其实就是先平移到指定位置,在指定位置进行了旋转之后又对画布做了返回平移处理,这样就实现了以自定义点为中心旋转画布的效果。
2
.6.2 scale
scale(float sx, float sy, float px, float py);
源码:
/**
* Preconcat the current matrix with the specified scale.
*
* @param sx The amount to scale in X
* @param sy The amount to scale in Y
* @param px The x-coord for the pivot point (unchanged by the scale)
* @param py The y-coord for the pivot point (unchanged by the scale)
*/
public final void scale(float sx, float sy, float px, float py) {
if (sx == 1.0f && sy == 1.0f) return;
translate(px, py);
scale(sx, sy);
translate(-px, -py);
}
同理,也是先实现平移,在指定位置缩放之后又对画布做了返回平移处理,从而实现了以自定义点为中心缩放画布
的效果。
2
.6.3 skew
/**
* @params sx 将画布在x方向上倾斜相应的角度,sx倾斜角度的tan值,其实就是将y逆时针旋转相应的角度
* @params sy 将画布在y方向上倾斜相应的角度,sx倾斜角度的tan值,其实就是将x顺时针旋转相应的角度
*
* 水平错切
*/
canvas.skew(1, 0);
canvas.drawRect(rect, mPaint);
对于点p(x0, y0),错切skew(sx,sy)后坐标(x,y),经过下面的转换:
x=x0 + sx*y0
y=y0 + sy*x0
当sx=1时,即将画布在x方向上旋转45度,其实就是x轴保持方向不变,y轴逆时针旋转45度。
当sy=1时,即将画布在y方向上旋转45度,其实就是y轴保持方向不变,x轴顺时针旋转45度。
3、状态保存与恢复
3.1 saveFlags
3.2 save
//画布状态保存与恢复,
int layerId = canvas.save();
canvas.restore();
canvas.restoreToCount(layerId);
3.3 saveLayer
关键方法:
//新建图层
public int saveLayer(float left, float top, float right, float bottom, Paint paint, int saveFlags)
//切换到指定图层的上一级图层
public void restoreToCount(int saveCount) {
//获取图层数量
public int getSaveCount()
代码:
canvas.saveLayer(0, 0, 200, 200, mPaint);
canvas.saveLayerAlpha(0, 0, 200, 200, 100);
canvas.restore();
canvas.restore();
4、应用
4.1 时钟
重写onDraw方法:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 绘制时间
drawTime(canvas);
// 绘制刻度盘
drawPanel(canvas);
}
绘制刻度盘:
for (int i = 1; i <= 60; i++) {
canvas.save();
canvas.rotate(360 / 60 * i, mWidth / 2, mHeight / 2);
canvas.translate(mWidth / 2, 0);
if (i % 5 == 0) {
canvas.drawLine(0, 0, 0, 30, mPaint);
//显示数字
String text = i / 5 + "";
//获取数字的宽度
mPaint.getTextBounds(text, 0, text.length(), mRect);
canvas.drawText(text, (0 - mRect.width()) / 2, 40 + mRect.height(), mPaint);
} else {
canvas.drawLine(0, 0, 0, 15, mPaint);
}
canvas.restore();
}
绘制时间:
//时针
canvas.save();
canvas.rotate(360 * mHour / 12, mWidth / 2, mHeight / 2);
canvas.drawLine(mWidth / 2, mHeight / 2, mWidth / 2, 160, mPaint);
canvas.restore();
//分钟
canvas.save();
canvas.rotate(360 * mMinutes / 60, mWidth / 2, mHeight / 2);
canvas.drawLine(mWidth / 2, mHeight / 2, mWidth / 2, 140, mPaint);
canvas.restore();
//秒针
canvas.save();
canvas.rotate(360 * mSeconds / 60, mWidth / 2, mHeight / 2);
canvas.drawLine(mWidth / 2, mHeight / 2, mWidth / 2, 100, mPaint);
canvas.restore();
4.2 刮刮乐
初始化画笔:
mPaint = new Paint();
mPaint.setColor(Color.GRAY);
mPathPaint = new Paint();
mPathPaint.setColor(Color.GRAY);
mPathPaint.setStrokeWidth(30);
mPathPaint.setStyle(Paint.Style.FILL);
mPathPaint.setStrokeJoin(Paint.Join.ROUND);
//采用XOR绘制,擦除灰色蒙层,从而显示出底部奖品图
mPathPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.XOR));
绘制:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//绘制奖品结果图
canvas.drawBitmap(mBitmap,
(mWidth - mBitmap.getWidth()) / 2,
(mHeight - mBitmap.getHeight()) / 2, mPaint);
//绘制灰色蒙层
canvas.drawBitmap(mGrayBm, 0, 0, mPaint);
mGrayCanvas.drawRect(0, 0, mWidth, mHeight, mPaint);
mGrayCanvas.drawPath(mPath, mPathPaint);
}
滑动事件处理:
private float mMoveX, mMoveY;
@Override
public boolean onTouchEvent(MotionEvent event) {
mMoveX = event.getX();
mMoveY = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mPath.moveTo(mMoveX, mMoveY);
invalidate();
return true;
case MotionEvent.ACTION_MOVE:
float endX = event.getX();
float endY = event.getY();
mPath.quadTo((endX - mMoveX) / 2 + mMoveX,
(endY - mMoveY) / 2 + mMoveY, endX, endY);
invalidate();
return true;
}
return super.onTouchEvent(event);
}