Canvas 画布 基础详解

前言

Canvas本意是画布的意思,然而将它理解为绘制工具一点也不为过。通过Canvas提供的API,你可以在画布上绘制出绝大部分图形,再配合上一些操作画布的API,比如旋转剪裁等变换画布的操作,就能够巧妙地画出更加复杂的图形。本文将通过结合实例带你深入学习 Android 中的 Canvas。

drawXXX系列

canvas.drawArc

方法:

drawArc(RectF oval,floatstartAngle,floatsweepAngle,booleanuseCenter,Paint paint) drawArc(floatleft,floattop,floatright,floatbottom,floatstartAngle,floatsweepAngle,booleanuseCenter, Paint paint)

画的方向为顺时针

对参数的解释:

userCenter若为true表示此弧会和RectF中心相连形成扇形,否则,弧的两头直接相连形成图形。

startAngle,负数或大于360则对360模除。

sweepAngle,大于360,则画出一圈。

角度:以RectF中心为坐标中心,中心所在直线为水平线,负角度弧斜上走,正角度弧斜下走,或者说以时钟三点钟为0度,顺时针为正,逆时针为负。

例子:

mPaint.setAntiAlias(true); mPaint.setColor(Color.RED); RectF mRecF=newRectF(20,20,200,200); canvas.drawArc(mRecF,-45,135,true,mPaint);//以斜上45度为起点,顺时针扫过135度

useCenter=true

image

useCenter=false

image

canvas.drawCircle

方法:

drawCircle(floatcx,floatcy,floatradius, Paint paint)

对参数的解释:

cx,cy为所画圆的中心坐标,radius为圆的半径

例子

mPaint.setAntiAlias(true);mPaint.setColor(Color.RED);canvas.drawCircle(100,100,80,mPaint);

圆心为(100,100),半径为80

image

注意:当画笔设置了StrokeWidth时,圆的半径=内圆的半径+StrokeWidth/2

canvas.drawBitmap

方法1:

drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint)

对参数的解释:

-bitmap:要画在画布上的位图

-matrix:构建的矩阵作用于将要画出的位图

方法2:

drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint)

对参数的解释:

-src:可为null,表示画整个位图,否则只花出位图的一块矩形区域图.subset of bitmap

-dst:定义的一个矩形范围,位图会平移或缩放来将自身放入矩形内

方法3:

drawBitmap(Bitmap bitmap,floatleft,floattop, Paint paint)

方法4:

drawBitmapMesh(Bitmap bitmap,intmeshWidth,intmeshHeight,float[] verts,intvertOffset,int[] colors,intcolorOffset, Paint paint)

网格扭曲,水波等的绘制

知识:https://www.zybuluo.com/cxm-2016/note/506317

例子:

方法1:

mPaint.setAntiAlias(true);      mPaint.setColor(Color.RED);      Matrix matrix =newMatrix();      matrix.postTranslate(100,0);//左移100matrix.postRotate(45);//顺时针旋转45度canvas.drawBitmap(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher),matrix,mPaint);

image

方法2:

Rect src =newRect(20,20,40,40);//取bitmap上src区域的部分图像Rect dst =newRect(100,100,200,200);//绘制的最终区域,一定填满mPaint.setAntiAlias(true);    mPaint.setColor(Color.RED);    canvas.drawBitmap(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher),src,dst,mPaint);

image

方法3:

canvas.drawBitmap(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher), 100, 100,mPaint);

image

canvas.drawColor,drawRGB

方法:

drawColor(intcolor, PorterDuff.Mode mode)

画整个画布的背景,但若区域受到剪裁,则只绘制剪裁区域的背景. 关键类PorterDuff.Mode

方法:drawRGB(int r, int g, int b)

同上

canvas.drawLine(s)

方法1:

drawLine(floatstartX,floatstartY,floatstopX,floatstopY, Paint paint)

对参数的解释:

- 前四个参数为直线的起点和终点的XY轴坐标

方法2:

drawLines(float[] pts,Paint paint)

方法3:

drawLines(float[] pts,intoffset,intcount, Paint paint)

对参数的解释:

-pts:待画的坐标点数组,格式为(x1,y1,x2,y2,...),至少4个值

-offset:要跳过坐标点数组中几个值才开始画(必须是4的倍数)

-count:至少为2,offset之后数组的大小。

例子

方法1:

mPaint.setAntiAlias(true);mPaint.setColor(Color.RED);mPaint.setTextSize(16);canvas.drawText("起点(20,100)", 22, 100,mPaint);canvas.drawText("终点(50,100)", 52, 150,mPaint);canvas.drawLine(20, 100, 50, 150,mPaint);

image

方法2:

mPaint.setAntiAlias(true);      mPaint.setColor(Color.RED);      mPaint.setTextSize(16);      canvas.drawText("A1(20,100)",0,90, mPaint);      canvas.drawText("A2(100,350)",40,370, mPaint);      canvas.drawText("B1(100,100)",80,90, mPaint);      canvas.drawText("B2(180,350)",150,370, mPaint);float[] points=newfloat[]{20,100,100,350,100,350,100,100,100,100,180,350};//至少4个值,即能够绘制一条直线canvas.drawLines(points,mPaint);

image

方法3:

mPaint.setAntiAlias(true);      mPaint.setColor(Color.RED);      mPaint.setTextSize(16);      canvas.drawText("A1(100,350)",40,370, mPaint);      canvas.drawText("B2(100,100)",80,90, mPaint);      canvas.drawText("B3(180,350)",150,370, mPaint);float[] points=newfloat[]{20,100,100,350,100,350,100,100,100,100,180,350};//至少4个点canvas.drawLines(points,4,8,mPaint);

image

canvas.drawRect

方法1:

voiddrawRect(floatleft,floattop,floatright,floatbottom, Paint paint)

确定矩形四个顶点的位置配上画笔即可

方法2:

voiddrawRect(Rect r, Paint paint)

矩形的四个位置为整型时使用

方法3:

voiddrawRect(RectF r, Paint paint)

方法1的另一简版,矩形的四个位置为浮点型时使用

例子:

mPaint.setAntiAlias(true); mPaint.setColor(Color.RED); canvas.drawRect(newRectF(20f,20f,120f,120f), mPaint);//canvas.drawRect(new Rect(20, 20, 120, 120), mPaint); 

image

canvas.drawOval

绘制椭圆

类似drawRect

canvas.drawPaint

方法:

drawPaint(Paint paint)

自定义的paint画在整个画布上,等于用paint在画布上画一个无限大的矩形,但当前画布受到剪裁,则染色区域仅限于剪裁部分。

canvas.drawPoint(s)

绘制点,方法基本类似drawLine(s)

canvas.drawRoundRect

方法1:

drawRoundRect(RectF rect,floatrx,floatry, Paint paint)

方法2:

drawRoundRect(floatleft,floattop,floatright,floatbottom,floatrx,floatry, Paint paint)

对参数的解释:

-rx,ry表示leftleft+rxleftleft+ry所围区域做弧,其余三个角类似,当rx=ry>=(right-left)/2时表示画一个半径为rx(ry)的圆(刚好外接一个矩形)

例子

方法1:

mPaint.setAntiAlias(true);      mPaint.setColor(Color.RED);      RectF mRecf =newRectF(20,100,200,200);      canvas.drawRoundRect(mRecf,30,50, mPaint);

image

方法2:API level至少21,做法一样

canvas.drawText

方法1:

drawText(String text,floatx,floaty, Paint paint)

x,y位置开始画text

注意:其中y表示文字的基线(baseline)所在的坐标,说白了就是我们小学写字用的那种带有横线的本子(一般都是按照一条基线来写字是吧?),用于规范你写的字是否成一条直线,否则很多人写着写着就往上飘了。而x坐标就是文字绘制的起始水平坐标,但是每个文字本身两侧都有一定的间隙,故实际文字的位置会比x的位置再偏右侧一些。

图:

基线类似下图深绿色的横线

image

方法2:

drawText(CharSequence text,intstart,intend,floatx,floaty, Paint paint)

x,y位置上画出startend(不含end) 之间的字符CharSequence charSequence = "charSequence";

方法3:

drawText(char[] text,intindex,intcount,floatx,floaty, Paint paint)

对参数的解释:

-index:表示从第几个字符开始,

-count:表示截取的数组长度

- 字符数组的定义:char[] a="abc".toCharArray()

方法4:

drawTextOnPath(String text, Path path,floathOffset,floatvOffset, Paint paint)

对参数的解释:

-path:文本绘制的路径(关键)

-hOffset:相对于路径的水平偏移量

-vOffset:相对于路径的垂直偏移量

方法5:

drawTextOnPath(char[] text,intindex,intcount, Path path,floathOffset,floatvOffset, Paint paint)

方法3和4的合体

方法6:

drawTextRun(CharSequence text,intstart,intend,intcontextStart,intcontextEnd,floatx,floaty,booleanisRtl, Paint paint)

对参数的解释:

-contextStart:可选,直接=start

-contextEnd:可选,直接=end

-x,y:文字绘制起点

-isRt1(isRightToLeft):文字是否支持rtl

-0 <= contextStart <= start <= end <= contextEnd <= text.length

方法7:

drawTextRun(char[] text,intindex,intcount,intcontextIndex,intcontextCount,floatx,floaty,booleanisRtl, Paint paint)

方法3和方法6合体

```count = end - start, contextCount = contextEnd - contextStart.```

例子:

方法1:

mPaint.setAntiAlias(true);mPaint.setColor(Color.RED);mPaint.setTextSize(20);canvas.drawText("Canvas学习",50,100,mPaint);

image

方法2:

mPaint.setAntiAlias(true);      mPaint.setColor(Color.RED);      mPaint.setTextSize(20);      CharSequence charSequence="Canvas学习";      canvas.drawText(charSequence,1,charSequence.length(),30,50,mPaint);

image

方法3:

mPaint.setAntiAlias(true);      mPaint.setColor(Color.RED);      mPaint.setTextSize(20);char[] chars="Canvas学习".toCharArray();      canvas.drawText(chars,1,chars.length-1,30,50,mPaint);

效果图同方法2

方法4:

mPaint.setAntiAlias(true);      mPaint.setColor(Color.RED);      mPaint.setTextSize(20);      Path path=newPath();Stringtext="Canvas学习";      path.addCircle(100,100,50, Path.Direction.CCW);      canvas.drawTextOnPath(text,path,0f,0f,mPaint);

image

canvas.drawPath

方法:drawPath(Path path, Paint paint)

根据定义的路径画出图

例子:

mPaint.setAntiAlias(true);        mPaint.setColor(Color.RED);        Path path=newPath();        path.addCircle(100,100,50, Path.Direction.CCW);        canvas.drawPath(path,mPaint);

效果等于画一个圆

canvas.clipxxx系列

canvas.clipPath

方法1:

clipPath(Path path) 

按所定义的路线剪裁,默认Region.Op.INTERSECT表示剪裁出相交的部分

方法2:

clipPath(Pathpath,Region.Opop)

解释:用指定的路径path修改当前的剪裁

对op参数的理解:以剪裁两次的区域分别为A,B来区别

-Region.Op.DIFFERENCE:剪裁出差异的部分,类似A-B部分

-Region.Op.REPLACE:后剪裁B的覆盖剪裁的A

-Region.Op.REVERSE_DEFFERENCE:剪裁出差异的部分,类似B-A部分

-Region.Op.INTERSECT:剪裁出相交的部分,类似A交B部分

-Region.Op.UNION:剪裁出AB合并的部分,类似** AUB**

-Region.Op.XOR:是** (AUB)-(A交B)** 刚好与** A交B** 相对

方法3:

clipRect(Rect[F]rect,Region.Opop)[]表示可选

解释:用指定的矩形来修改当前的剪裁

方法4:

clipRect(Rect rect) 

剪裁一个矩形区域,还有其他能构造矩形的方法不再列出

例子(以剪裁路径为例):

首次剪裁

Path path=newPath();    path.addCircle(100,100,50, Path.Direction.CCW);    canvas.clipPath(path);    canvas.clipPath(path);    canvas.drawColor(Color.RED);//红色区域即为剪裁的区域 

由于clipPath方法剪裁模式默认为Region.Op.INTERSECT,故当前剪裁部分和整个画布相交即为本身。

image

剪裁模式(绿色区域为最终得到的剪裁部分)

mPaint.setAntiAlias(true); mPaint.setColor(Color.RED); canvas.drawColor(Color.BLUE); canvas.drawRect(newRectF(20,20,120,120), mPaint); canvas.drawCircle(120,70,50, mPaint); canvas.clipRect(newRectF(20,20,120,120)); Path path =newPath(); path.addCircle(120,70,50, Path.Direction.CCW); canvas.clipPath(path, Region.Op.INTERSECT); canvas.drawColor(Color.GREEN);

Region.Op.INTERSECT

image

Region.Op.REPLACE

image

Region.Op.REVERSE_DEFFERENCE

image

Region.Op.UNION

image

Region.Op.XOR

image

canvas的保存与恢复

解释:用来保存或恢复Canvas的状态

作用:save之后可以调用Canvas的平移、放缩、旋转、错切、裁剪等对当前画布进行操作,再进行相应的绘制,避免影响画布上已绘制的view,配合canvas.restore()(将当前画布恢复到初始状态) 使用

canvas的变幻操作

canvas.translate

方法:

canvas.translate(floatdx,floatdy)

作用:移动当前画布水平距离dx,竖直距离dy

例子:

mPaint.setAntiAlias(true);mPaint.setColor(Color.RED);canvas.drawColor(Color.BLUE);canvas.translate(100,100);canvas.drawCircle(0,0,50,mPaint);

image

canvas.scale

方法1:

canvas.scale(floatsx,floatsy)

作用:sx、syx、y方向上缩放的倍数,画布缩放后,再画出的图片相应的坐标都会进行缩放

例子:

mPaint.setAntiAlias(true); mPaint.setColor(Color.RED); canvas.drawColor(Color.BLUE); canvas.save(); canvas.scale(0.5f,0.5f);//x,y均缩小一半canvas.drawCircle(100,100,50,mPaint); canvas.restore(); mPaint.setColor(Color.WHITE); canvas.drawCircle(100,100,50,mPaint);

image

方法2:

canvas.scale (floatsx,floatsy,floatpx,floatpy)

作用:缩放画布并平移画布到基准点(px,py)

对参数的解释:

-px,py为缩放后画布新的坐标原点(也叫缩放基准点)

例子:

mPaint.setAntiAlias(true);canvas.drawColor(Color.BLUE);mPaint.setColor(Color.WHITE);canvas.drawCircle(100,100,50,mPaint);canvas.save();canvas.scale(0.5f,0.5f,100,100);mPaint.setColor(Color.RED);canvas.drawCircle(100,100,50,mPaint);canvas.restore();

image

canvas.rotate

方法:

canvas.rotate(floatdegrees)

作用:顺时针旋转当前画布一定角度,也可加入基准点坐标

例子:

mPaint.setAntiAlias(true); canvas.drawColor(Color.BLUE); mPaint.setColor(Color.WHITE); canvas.drawRect(newRectF(80,80,180,180),mPaint); canvas.save(); canvas.rotate(45);//canvas.rotate(45,200,200);mPaint.setColor(Color.RED); canvas.drawRect(newRectF(80,80,180,180),mPaint); canvas.restore();

无基准点

image

有基准点 (200,200)

image

canvas.skew

方法:

canvas.skew(floatsx,floatsy)

作用:画布的错切

sx:将画布在x方向上倾斜相应的角度,sx为倾斜角度的tan值;

sy:将画布在y轴方向上倾斜相应的角度,sy为倾斜角度的tan值;

比如在X轴方向上倾斜45度,tan45=1;

例子:

mPaint.setAntiAlias(true); canvas.drawColor(Color.BLUE); mPaint.setColor(Color.WHITE); canvas.drawRect(newRectF(0,0,180,180),mPaint); canvas.save(); canvas.skew(1,0);//画布X轴倾斜45度mPaint.setColor(Color.RED); canvas.drawRect(newRectF(0,0,180,180),mPaint); canvas.restore();

image

总结

以上大致介绍了Canvas类中众多绘制方法。首先,先对方法进行解析;其次,给出相应的示例代码并结合运行效果,旨在帮助读者更好地理解诸如上述绘制方法的基本使用;最后,对于方法的理解如有纰漏,欢迎指正。

你可能感兴趣的:(Canvas 画布 基础详解)