一、介绍
Canvas之为画布,但是并不是真的直接在Canvas画,而是bitmap默认会创建一个bitmap,也可以通过构造方法或者setBitmap方法传入,像素所有的信息画在了这个bitmap上。
二、drawBitmap()
共有6个重载方法,但是其中两个参数最多的已经废弃掉了,那么就学习4个吧!
在draw方法中,有一个很牛逼的方法:drawBitmapMesh,但是一般不会用到。简单处理图片我们一般会用到Metrix,但是遇到Metrix处理不了的,记得还可以研究一下drawBitmapMesh。

public void drawBitmap(@NonNull Bitmap bitmap, float left, float top, @Nullable Paint paint) {
super.drawBitmap(bitmap, left, top, paint);
}
//使用
canvas.drawBitmap(srcBitmap,0,0,paint);
- bitmap 原始图片
- left 图片的左上角的X轴坐标
- top 图片的右上角的Y轴坐标
- paint 画笔
public void drawBitmap(@NonNull Bitmap bitmap, @Nullable Rect src, @NonNull Rect dst,
@Nullable Paint paint) {
super.drawBitmap(bitmap, src, dst, paint);
}
//使用
canvas.drawBitmap(srcBitmap,new Rect(0,0,720,500), new Rect(0,0,720,500),paint);
- src 剪切区域
- dst view中的显示位置,可以拉伸或缩放
public void drawBitmap(@NonNull Bitmap bitmap, @Nullable Rect src, @NonNull RectF dst,
@Nullable Paint paint) {
super.drawBitmap(bitmap, src, dst, paint);
}
//使用
canvas.drawBitmap(srcBitmap,new Rect(0,0,720,500), new RectF(0,0,720,500),paint);
public void drawBitmap(@NonNull Bitmap bitmap, @NonNull Matrix matrix, @Nullable Paint paint) {
super.drawBitmap(bitmap, matrix, paint);
}
//使用
Matrix matrix = new Matrix();
matrix.setTranslate(20f,20f);
canvas.drawBitmap(srcBitmap,matrix,paint);
- matrix 一个3 * 3的矩阵,矩阵在后面会学习到,在这里不做仔细说明了,现在也不懂
三、drawLines
3.1 画一条直线:

public void drawLine(float startX, float startY, float stopX, float stopY,
@NonNull Paint paint) {
super.drawLine(startX, startY, stopX, stopY, paint);
}
//使用
canvas.drawLine(0,0,500,500,paint);
- startX 起点X轴的坐标
- startY 起点Y轴的坐标
- stopX 终点X轴的坐标
- stopY 终点Y轴的坐标
- paint 画笔
3.2 画多条直线:

public void drawLines(@Size(multiple = 4) @NonNull float[] pts, @NonNull Paint paint) {
super.drawLines(pts, paint);
}
//使用
canvas.drawLines(new float[]{0,0,500,500,10,0,900,200},paint);
- pts 坐标数组,4个数值为一组,分别表示一条直线的两端坐标。源码中注解:@Size(multiple = 4) 需要是4的倍数
3.3 画多条直线

public void drawLines(@Size(multiple = 4) @NonNull float[] pts, int offset, int count,
@NonNull Paint paint) {
super.drawLines(pts, offset, count, paint);
}
//使用
canvas.drawLines(new float[]{0,0,500,500,10,0,900,200},4,4,paint);
- offset 要跳过的数组中数的个数,为4,则代表数组中前4位无效
- count 数组中有效数的数量 总共8个,跳过4个,count就为4
四、drawPoint
4.1 画一个点

public void drawPoint(float x, float y, @NonNull Paint paint) {
super.drawPoint(x, y, paint);
}
//使用
canvas.drawPoint(100f,100f,paint);
4.2 画多个点

public void drawPoints(@Size(multiple = 2) @NonNull float[] pts, @NonNull Paint paint) {
super.drawPoints(pts, paint);
}
//使用
canvas.drawPoints(new float[]{100f,100f,300f,200f},paint);
- 两个点为一组,表示一个点的坐标位置;
源码中注解:@Size(multiple = 2) 长度须是2的倍数,如果数据中有5个值,生效的只有前4个
4.3 画多个点
public void drawPoints(@Size(multiple = 2) float[] pts, int offset, int count,
@NonNull Paint paint) {
super.drawPoints(pts, offset, count, paint);
}
//使用
canvas.drawPoints(new float[]{100f,100f,300f,200f},2,2,paint);
- offset 要跳过的数量,跳过的数值时无效的
- count 数组的有效数据量
五、drawPath
5.1 moveTo、lineTo、close
moveTo指定路径的开始坐标位置,lineTo过程坐标位置,可以为多个。close路径绘制关闭,将终点与起点连接起来,绘制一个等腰三角形:

path = new Path();
path.moveTo(360,20);
path.lineTo(200,220);
path.lineTo(520,220);
path.close();//关闭
canvas.drawPath(path,paint);
绘制路径用到Path,首先我们先创建一个Path对象,通过moveTo指定起始坐标点,lineTo需要绘制的路径坐标。close关闭并连接终点与起点。条用drawPath进行绘制。在绘制路径时,需要将Paint的Style指定为STROKE。
5.2 quadTo
可以来绘制二阶贝塞尔曲线,也就是3个点确定一个曲线,由3个点来确定:(100,100),(200,200),(900,100)

Path path = new Path();
path.moveTo(100f,100f);
float[] floats = new float[]{200f,200f,900f,100f};
path.quadTo(200f,200f,900f,100f);
canvas.drawPath(path,paint);
canvas.drawPoints(floats,paint);
5.3 cubicTo
此方法与quadTo基本相同,多了一个点。也就是quadTo3个点确定一个贝塞尔曲线,而cubicTo是四个点。

Path path = new Path();
path.moveTo(100f,100f);
path.cubicTo(200f,200f,400f,100f,700f,200f);
canvas.drawPath(path,paint);
5.4 arcTo
在规定区域内绘制一个圆弧,并判断圆弧的起始点和路径的起始点是否为同一点,不同则连接

Path path = new Path();
path.moveTo(100f,100f);
RectF rect = new RectF(200, 200, 400, 400);
path.arcTo(rect,0,90);
canvas.drawPath(path,paint);
我们一起看一下这个绘制流程:首先创建了一个路径Path,指定了起始位置,rect指的是一个矩形,arcTo会在这个矩形中根据指定的弧度绘制圆弧,0,90就是上图所示。最后并将圆弧的起始点与路径的起始点连接在一起。
5.5 rLineTo
r是Relative的缩写,相对的意思。rLineTo绘制时以path最后一个点为坐标原点(0,0),这里是(100,100);lineTo、rLineTo起始点默认是屏幕左上角的坐标系原点(0,0)!

Path path = new Path();
path.moveTo(100f, 100f);
path.rLineTo(300, 200);
canvas.drawPath(path, paint);
canvas.drawPoint(300, 200, paint);
在绘制过程中,我们指定的终点坐标为(300,200),但实际点点坐标为(400,300)。原因是相对于起始点进行计算的,在这里起始点(100,100)就相当于是(0,0);
5.6 addArc
与arcTo方法的区别是:不会把圆弧的起始点和路径的起始点连接在一起.

Path path = new Path();
path.moveTo(100,100);
path.lineTo(200,200);
RectF rect = new RectF(300,300,500,400);
path.addArc(rect,0,90);
canvas.drawPath(path,paint);
5.7 addOval、drawTextOnPath 在路径上绘制文字

Path path = new Path();
path.moveTo(100f,100f);
Paint textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
textPaint.setTextSize(30f);
RectF rectF = new RectF(300,300,490,490);
path.addOval(rectF, Path.Direction.CW);
// path.addOval(rectF, Path.Direction.CCW);//改变闭合方向,文字会内侧且逆时针绘制
canvas.drawPath(path,paint);
char[] chaars = new char[]{'a','b','c','d','e'};
canvas.drawTextOnPath(chaars,0,5,path,0f,5,textPaint);
Path.Direction.CCW 改变闭合方向,文字会内侧且逆时针绘制。
5.8 drawTextRun

Paint textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
textPaint.setTextSize(60f);
char[] chars = new char[]{'a', 'b', 'c', 'd', 'e'};
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
canvas.drawTextRun(chars, 0, chars.length, 0, chars.length, 100f, 100f, true, textPaint);
}
isRtl 为true : 文字倒着绘制,此方法必须在API大于23的时候才能使用。
5.9 clipRect裁剪规则区域

Rect rect = new Rect(0,0,300,300);
canvas.drawColor(Color.BLUE); //绘制背景色
canvas.clipRect(rect); //剪切画布
canvas.drawColor(Color.RED); //剪切后的画布背景色
canvas.drawRect(100,100,400,400,new Paint(Paint.ANTI_ALIAS_FLAG)); //看一下剪切的画布是否生效
我们指定裁剪画布的区域是(0,0,300,300),也就是后红色的区域为我们裁剪后的画布。为了验证裁剪画布是否生效,我们又画了一个矩形,这个矩形是(100,100,400,400),很明显没有绘制完整,因为矩形绘制的区域超出了现有画布的区域。
5.10 rotate画布旋转

public void rotate(float degrees) {
if (degrees == 0.0f) return;
nRotate(mNativeCanvasWrapper, degrees);
}
canvas.rotate(30); //画布旋转
5.11 op方法
这个方法的作用是:处理画布多次裁剪。

Rect rect1 = new Rect(100,100,300,300);
Rect rect2 = new Rect(200,200,400,400);
canvas.drawColor(Color.BLUE);//背景色 蓝色
canvas.save(); //保存画布
canvas.clipRect(rect1); //绘制第一块区域
canvas.clipRect(rect2, Region.Op.XOR); //绘制第二块区域
//截取后有效区域绘制红色
canvas.drawColor(Color.RED);
canvas.restore();
//绘制辅助区域
canvas.drawRect(100,100,300,300,paint);
canvas.drawRect(200,200,400,400,paint);
首先呢,创建两个矩形,用于裁剪画布。指定画布的背景色为蓝色,使用clipRect裁剪规则画布,这里指定的op为XOR,取两次绘制的非交集部分。
Region.Op.DIFFERENCE 取第一次剪切的非交集部分:

Region.Op.INTERSECT 取两次剪切的交集部分:

Region.Op.REPLACE 第二次代替第一次剪切:

Region.Op.UNION 两次剪切的和:

Region.Op.REVERSE_DIFFERENCE 第二次剪切的非交集部分 :

5.12 clipPath 裁剪不规则画布

Path path = new Path();
path.addCircle(100,100,100, Path.Direction.CW); //裁剪不规则图形
canvas.drawColor(Color.BLUE);
canvas.clipPath(path);
canvas.drawColor(Color.RED);
//绘制辅助圆
canvas.drawCircle(100,100,100,paint);
用Path指定了一个圆形。
5.13 save restore
Rect path1 = new Rect(100,100,300,300);
Rect path2 = new Rect(150,150,200,200);
canvas.translate(500,200); //画布平移
canvas.drawColor(Color.BLUE);
canvas.clipRect(path1);
canvas.drawColor(Color.RED);
canvas.save(); //保存当前层
canvas.rotate(10); //旋转
canvas.clipRect(path2);
canvas.drawColor(Color.GREEN);
canvas.restore(); //把图层恢复到最后一次save()前的状态
- save 保存当前层
- restore 把图层恢复到最后一次save()前的状态
- 关于保存图层,还有一个更加强大的saveLayer(),这个方法就等用到时,再进行学习
5.14 scale缩放

Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.img2);
canvas.scale(0.2f,0.2f); //缩放的值为 0 - 1f 1代表不缩放 默认的缩放中心是(0,0)
canvas.drawBitmap(bitmap, 0, 0, paint);

canvas.scale(0.2f, 0.2f, 360, 0); //指定缩放中心 (360,0)
5.15 skew 错切

Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.img2);
canvas.skew(0.3f,0);
canvas.drawBitmap(bitmap, 0, 0, paint);
- sx 将画布在x方向上倾斜相应的角度,sx倾斜角度的tan值,其实就是将y逆时针旋转相应的角度
- sy 将画布在y方向上倾斜相应的角度,sx倾斜角度的tan值,其实就是将x顺时针旋转相应的角度
来源:http://www./content-4-201651.html
|