做者:宋者为王html
链接:https://cnblogs.com/andy-songwei/p/10960012.htmlcanvas
上一篇讲 View 的绘制流程中讲到过,最后一步是 draw 流程,在这个过程当中,子 view 须要重写 onDraw 方法来画出本身的内容。在自定义 View 绘制自身内容的时候,系统提供了 3 个很是重要的类来帮助开发者画各类炫酷的图形:Canvas、Paint、Path。本篇主要介绍 Canvas 相关的内容,Paint 和 Path 在后面会单独再作介绍。官方文档中介绍的 Canvas 相关的 API 不少,本文主要介绍和梳理一些比较经常使用的实用功能。数组
本文的主要内容以下:app
以下代码展现了一个自定义 view 画图形的一个很是简单的示例。这里 onDraw 方法的参数 Canvas 就是本篇的主角了,中文意思“画布”,意思就是全部“画”的内容都是在这张画布上完成的。ide
Paint paint = new Paint();
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 绘制一个原点坐标(300,300),半径为200的圆
canvas.drawCircle(300, 300, 200, paint);
}
代码很是简单,可见自定义绘制上手很是容易。函数
Canvas 包含了一些画基本图案的函数,基本都是以 drawXXX 的形式给出的。post
这里先简单介绍一下画图中所参照的坐标系,是以当前 View 位置的左上角为原点(0,0),水平方向向右为 X 轴正方向,竖直向下为 Y 轴正方向,这里的 View 位置是个相对值,它取决于开发者把它放在哪里。坐标系大体以下所示,注意和平时咱们数学上坐标系略有差异。spa
在 Canvas 的这些 drawXXX 方法中会用到 paint 类,它是画笔,会决定绘制出来的图形的颜色,是填充整个图形仍是仅绘制边框线条等多个属性。这些会在之后专门介绍 Paint 的时候再讲,这里先提醒读者注意,在笔者截取的效果图中,我们这里先只关注形状,关于 piant,一概先用默认的填充。3d
函数原型:drawColor(@color int color)。rest
做用:将整个绘制区域填充为指定颜色(能够设置透明度)。
示例:通常有三种方式来引用颜色值
//使用系统提供的颜色
canvas.drawColor(Color.BLACK);
//使用自定义颜色
canvas.drawColor(Color.parseColor("#000000"));
//使用color.xml中定义的颜色值
canvas.drawColor(getResources().getColor(R.color.black));
其它设置颜色的方法
1)drawRGB(int r, int g, int b):根据 RGB 值来设置颜色
2)drawARGB(int a, int r, int g, int b):根据透明度和 RGB 的值来设置颜色。
上述中的几种方法,适用于在绘制前设置底色,或者在绘制完成后添加一层半透明蒙板。
函数原型 drawCircle(float centerX, float centerY, float radius, Paint paint)。参数依次为:X 坐标,Y 坐标,半径,画笔。
做用:以原点(centerX,centerY),半径 radius,画一个圆。
示例:
// 绘制一个原点坐标(300,300),半径为200的圆
canvas.drawCircle(300, 300, 200, paint);
函数原型:drawRect(float left, float top, float right, float bottom, @NonNull Paint paint) 参数分别为左边、顶部、右边、底部四条边的坐标值。
根据给定的 4 条边框的坐标,来画矩形。
示例:
canvas.drawRect(100, 100, 500, 500, paint);
其余函数
1) drawRect(@NonNull Rect r, @NonNull Paint paint)。实际上就是将前面函数定义为一个 Rect 来做为参数,做用和上面同样。
2)示例,效果和上述同样。
canvas.drawRect(new Rect(100,100,500,500),mPaint);
函数原型:drawPoint(float x, float y, @NonNull Paint paint)。参数 x,y 分别为该点的坐标,点的大小和形状由 paint 决定。
功能:在指定 x,y 坐标处画点
示例
canvas.drawPoint(50, 50, paint);
drawPoints(float[] pts, int offset, int count,@NonNull Paint paint)。pts 这个数组是点的坐标,每两个成一对;offset 表示跳过数组的前几个数再开始记坐标;count 表示一共有多个数参与绘制。
示例:
float[] points = {0, 0, 50, 50, 50, 100, 100, 50, 100, 100, 150, 50};
canvas.drawPoints(points, 2 /* 跳过两个数,即前两个 0 */,
8 /* 一共绘制 8 个数(4 个点)*/, paint);
函数原型:drawOval(float left, float top, float right, float bottom, @NonNull Paint paint)。参数分别为四个顶点所在切线坐标。
做用:4 个参数肯定了一个矩形的 4 条边框,这个矩形肯定了一个椭圆。该函数用于画出这个指定的椭圆。
示例
canvas.drawOval(50, 50, 350, 200, paint);
函数原型:drawLine(float startX, float startY, float stopX, float stopY, Paint paint)。参数值分别为起始点坐标和结束点坐标。
做用:根据给定的起始点和结束点画直线
示例
canvas.drawLine(200, 200, 800, 500, paint);
函数原型:drawArc(float left, float top, float right, float bottom, float startAngle,float sweepAngle, boolean useCenter, @NonNull Paint paint)。扇形或者弧线,都是椭圆(圆能够当作是椭圆的特殊情形)上的一部分,因此画扇形或者弧线须要先肯定好椭圆,前 4 个参数就是用于肯定这个椭圆。startAngle 表示起始角度,X 轴正方向(即水平向右方向)为 0 度,顺时针为正角度,逆时针为负角度。sweepAngle 表示弧线/扇形划过的角度,依然是顺时针为正,逆时针为负;useCenter 表示是否连到圆心,true 表示连到,表示扇形,false 表示不连到,表示弧线。
示例:
canvas.drawArc(200, 100, 800, 500, -110, 100, true, paint); // 绘制扇型
canvas.drawArc(200, 100, 800, 500, 20, 140, false, paint); // 绘制弧形
函数原型:drawPath(Path path, Paint paint)
根据 path 定义的形状来绘制。这个会在后续文章中详细讲。
函数原型:drawBitmap(Bitmap bitmap, float left, float top, Paint paint)。参数 bitmap 表示要绘制的图片对象;left,top 表示要显示的 bitmap 对象的左上角左边位置。
做用:把指定的 bitmap 对象中的像素复制到指定位置。
示例:
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.test);
canvas.drawBitmap(bitmap,100,50,paint);
drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint);
drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint);
drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint);
它们能够指定复制原 bitmap 中的指定区域(Rect src 来肯定),到画布中的指定位置(Rect dst)来肯定。
函数原型:drawText(String text, float x, float y, Paint paint)。界面里全部的显示内容,都是绘制出来的,包括文字。drawText() 这个方法就是用来绘制文字的。参数 text 是用来绘制的字符串, x 和 y 是绘制的起点坐标。文字的绘制在后面也会单独详细说明。
根据给定的范围,对指定的 bitmap 进行裁剪,裁剪以后再进行绘制。范围裁剪有两个方法:clipRect()和 clipPath()。前者会截取一个矩形范围,然后者 path 指定的形状更多,因此裁剪的形状也会更多。
在裁剪的过程当中,要加上这两句代码。它们用于保存和恢复绘制范围,若是不加容易出现干扰。
canvas.save();
//目标bitmap
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.test);
//肯定须要裁剪的矩形范围
canvas.clipRect(left, top, right, bottom);
//在指定的x,y坐标开始绘制裁剪后的bitmap
canvas.drawBitmap(bitmap, x, y, paint);
canvas.restore();
裁剪后的效果以下图所示:
Canvas.clipRect(Path path) 用法彻底同样,只是把参数换成了 Path ,因此能裁切的形状更多一些。其对应有一个方法 Canvas.clipOutPaht(Path path),反向裁剪,效果能够从截图中看出来。
canvas.save();
canvas.clipPath(path1);
canvas.drawBitmap(bitmap, point1.x, point1.y, paint);
canvas.restore();
canvas.save();
canvas.clipOutPath(path);
canvas.drawBitmap(bitmap, point2.x, point2.y, paint);
canvas.restore();
这个功能对显示原型头像比较有帮助。
几何变换的使用大概分为三类:使用 Canvas 来作常见的二维变换;使用 Matrix 来作常见和不常见的二维变换;使用 Camera 来作三维变换。
Canvas.translate(float dx, float dy) 平移。参数里的 dx 和 dy 表示横向和纵向的位移。
Canvas.rotate(float degrees, float px, float py) 旋转
Canvas.scale(float sx, float sy, float px, float py)放大缩小
Canvas.skew(float sx, float sy) 错切,就是倾斜的意思。
canvas.save();
//水平向X轴正方向移动200px
canvas.translate(200, 0);
//以给定的点为轴旋转45度
canvas.rotate(45, centerX, centerY);
//以图片中心为轴,水平和竖直方向各放大为原来的1.3倍
canvas.scale(1.3f, 1.3f, x + bitmapWidth / 2, y + bitmapHeight / 2);
canvas.skew(0, 0.5f);
canvas.drawBitmap(bitmap, x, y, paint);
canvas.restore();
使用 Matrix 能够作常规的几何变换,还能够对图形进行自定义变换。在作常规的几何变换时,和前面介绍的用 Canvas 实现常规变换,功能同样,选其一便可。
使用 Matrix 来作常规变换主要分三个步骤:
建立Matrix对象;
Matrix.pre/postTranslate/Rotate/Scale/Skew()设置几何变换;
Canvas.setMatrix(matrix)或Canvas.concat(matrix)把几何变换应用到Canvas中(尽可能用后者)。
//1.建立Matrix对象
Matrix matrix = new Matrix();
matrix.reset();
//2.几何变换
matrix.postTranslate(0,100);
matrix.postRotate(45,bitmap.getWidth()/2,bitmap.getHeight()/2);
matrix.postScale(1.3f,1.3f,x+bitmap.getWidth()/2,y+bitmap.getHeight()/2);
matrix.postSkew(0,0.5f);
canvas.save();
//3.把几何变换应用到Canvas中
canvas.concat(matrix);
canvas.drawBitmap(bitmap,x,y,paint1);
canvas.restore();