Android自定义View(七)Canvas学习

一、介绍

Canvas称之为画布,但是并不是直接在Canvas画,而是canvas默认会创建一个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);
  • 与上一个重载方法基本相同,区别是dst为浮点类型
public void drawBitmap(@NonNull Bitmap bitmap, @NonNull Matrix matrix, @Nullable Paintpaint) {
   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);
  • x X轴的坐标
  • y Y轴的坐标

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); //画布旋转
  • degrees 旋转度数

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,30
Rect path2 = new Rect(150,150,200,20
canvas.translate(500,200); //画布平移
canvas.drawColor(Color.BLUE);
canvas.clipRect(path1);
canvas.drawColor(Color.RED);
canvas.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顺时针旋转相应的角度
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值