自定义View ——Canvas之绘制基本形状##
转载出处:http://www.gcssloop.com/customview/Canvas_Convert/
一.Canvas简介###
Canvas 称之为画布,是安卓平台2D图形绘制的基础,非常强大。
一般来说,比较基础的东西有两大特点:
1.可操作性强:由于这些是构成上层的基础,所以可操作性必然十分强大。
2.比较难用:各种方法太过基础,想要完美的将这些操作组合起来有一定难度。
本系列文章不仅会介绍到Canvas的操作方法,还会简单介绍一些设计思路和技巧。
二.Canvas的常用操作速查表##
列表:
操作类型 | 相关API | 备注 |
---|---|---|
绘制颜色 | drawColor,drawRGB,drawARGB | 使用单一颜色填充整个画布 |
绘制基本形状 | drawPoint,drawPoints,drawLine,drawLines,drawRect,drawRountRect,drawOval,drawCircle,drawArc | 依次为点、线、矩形、圆角矩形、椭圆、圆、圆弧 |
绘制图片 | drawBitmap,drawPicture | 绘制位图和图片 |
绘制文本 | drawText,drawPosText,drawTextOnPath | 依次为 绘制文字、绘制文字时指定每个文字位置、根据路径绘制文字 |
顶点操作 | drawVertices,drawBitmapMesh | 通过对顶点操作可以使图像形变,drawVertices直接对画布作用、drawBitmapMesh只对绘制的Bitmap作用 |
绘制路径 | drawPath | 绘制路径,绘制贝塞尔曲线时也需要用该函数 |
画布剪裁 | clipPath,clipRect | 设置画布的显示区域 |
画布快照 | save,restore,saveLayerXxx,restoreToCount,getSaveCount | 依次为保存当前状态、回滚到上一次保存的状态、保存图层状态、回滚到指定状态、获取保存次数 |
画布变换 | translate,scale,rotate,skew | 依次为位移、缩放、旋转、错切 |
Matrix矩阵 | getMatrix、setMatrix、concat | 实际画布的位移,缩放等操作的都是图像矩阵Matrix,只不过Matrix比较难以理解和使用,故封装了一些常用的方法。 |
三、Canvas详解###
本篇内容主要讲解如何利用Canvas绘制基本图形。
绘制颜色:
绘制颜色是填充整个画布,常用于绘制底色。
代码:
canvas.drawColor(Color.BLUE);//绘制蓝色
如图:
创建画笔:
想绘制内容,首先需要先创建一个画笔,如下:
//创建一个画笔
private Paint mPaint=new Paint();
//初始化画笔
private void initPaint(){
mPaint.setColor(Color.BLACK); //设置画笔颜色
mPaint.setStyle(Paint.Style.FILL); //设置画笔模式为填充
mPaint.setStrokeWidth(10f); //设置画笔宽度为10px
}
//在构造函数中初始化
public SloopView(Context context,AttributeSet attrs){
super(context,attrs);
initPaint();
}
在创建完画笔之后,就可以在Canvas中绘制各种内容了。
绘制点:###
可以绘制一个点,也可以绘制一组点,如下:
canvas.drawPoint(200,200,mPaint);
canvas.drawPoints(new float[]{
500,500,
500,600,
500,700
},mPaint);
关于坐标原点默认在左上角,水平向右为x轴增大方向,竖直向下为y轴增大方向。
绘制直线:###
绘制直线只需要两个点,初始点和结束点,同样绘制直线也可以绘制一条或者绘制一组:
canvas.drawLine(300,300,500,500,mPaint);//在坐标(300,300)(500,600)之间绘制一条直线
canvas.drawLines(new float[]{ //绘制一组线 每四位数字(两个点的坐标)确定一条线
100,200,200,200,
100,300,200,200
},mpaint);
绘制矩形:###
确定确定一个矩形最少需要四个数据,就是对角线的两个点的坐标值,这里一般采用左上角和右下角的两个点的坐标。
关于绘制矩形,Canvas提供了三种重载方法,第一种就是提供四个数值(矩形左上角和右下角两个点的坐标)来确定一个矩形进行绘制。其余两种是先将矩形封装为Rect或者RectF(实际上仍然是用两个坐标点来确定的矩形),然后传递给Canvas绘制,如下:
//第一种
canvas.drawRect(100,100,800,400,mPaint);
//第二种
Rect mRect=new Rect(100,100,800,400);
canvas.drawRect(mRect,mPaint);
//第三种
RectF mRectF=new RectF(100,100,800,400);
canvas.drawRect(mRectF,mPaint);
三种绘制的结果是完全一样的。
绘制圆角矩形###
绘制圆角矩形也提供了两种重载方式,如下:
//第一种
RectF mRectF=new RectF(100,100,800,400);
canvas.drawRoundRect(mRectF,30,30,mPaint);
//第二种
canvas.drawRoundRect(100,100,800,400,30,30,mPaint);
第二种方法在API21的时候才添加上,所以我们一般使用的都是第一种。
与矩形相比,圆角矩形多出来了两个参数rx和ry,这里圆角矩形的角实际上不是一个正圆的圆弧,而是椭圆的圆弧,这里的两个参数实际上是椭圆的两个半径,他们看起来如下图:
红线标注的rx与ry就是两个半径,也就是相比绘制矩形多出来的那两个参数。
我们了解到原理后,就可以为所欲为了,通过计算可知我们上次绘制的矩形宽度为700,高度为300,当你让rx大于350(宽度的一半),ry大于150(高度的一半)时奇迹就出现了,你会发现圆角矩形变成了一个椭圆,他们画出来是这样的(为了方便确认我更改了画笔颜色,同时绘制出了矩形和圆角矩形):
//矩形
RectF mRectF=new RectF(100,100,800,400);
//绘制背景矩形
mPaint.setColor(Color.GRAY);
canvas.drawRect(mRectF,mPaint);
//绘制圆角矩形
mPaint.setColor(Color.BLUE);
canvas.drawRoundRect(mRectF,700,400,mPaint);
其中灰色部分是我们所选定的矩形,而里面的圆角矩形则变成了一个椭圆,实际上rx为宽度的一半,ry为高度的一半时,刚好是一个椭圆,通过上面我们分析的原理推算一下就能得到,而当rx大于宽度的一半,ry大于高度的一半时,实际上是无法计算出圆弧的,所以drawRoundRect对大于该数值的参数进行了限制,凡是大于一半的参数均按照一半来处理。
绘制椭圆:###
相对于绘制圆角矩形,绘制椭圆就简单的多了,因为他只需要一个矩形作为参数:
//第一种
RectF rectF=new RectF(100,100,800,400);
canvas.drawOval(rectF,mPaint);
//第二种
canvas.drawOval(100,100,800,400,mPaint);
以上两种方法效果完全一样,但一般使用第一种。
绘制椭圆实际上就是绘制一个矩形的内切图形,原理如下:
绘制圆:###
如下:
canvas.drawCircle(500,500,400,mPaint);//绘制一个圆心坐标在(500,500),半径为400的圆。
绘制圆形有四个参数,前两个是圆心坐标,第三个是半径,最后一个是画笔。
绘制圆弧:
// 第一种
public void drawArc(@NonNull RectF oval, float startAngle, float sweepAngle, boolean useCenter, @NonNull Paint paint){}
// 第二种
public void drawArc(float left, float top, float right, float bottom, float startAngle,
float sweepAngle, boolean useCenter, @NonNull Paint paint) {}
从上面可以看出,相比于绘制椭圆,绘制圆弧还多了三个参数:
startAngle //开始角度
sweepAngle //扫过角度
useCenter //是否使用中心
上代码:
RectF rectF = new RectF(100,100,800,400);
// 绘制背景矩形
mPaint.setColor(Color.GRAY);
canvas.drawRect(rectF,mPaint);
// 绘制圆弧
mPaint.setColor(Color.BLUE);
canvas.drawArc(rectF,0,90,false,mPaint);
//-------------------------------------
RectF rectF2 = new RectF(100,600,800,900);
// 绘制背景矩形
mPaint.setColor(Color.GRAY);
canvas.drawRect(rectF2,mPaint);
// 绘制圆弧
mPaint.setColor(Color.BLUE);
canvas.drawArc(rectF2,0,90,true,mPaint);
上述代码实际上是绘制了一个起始角度为0度,扫过90度的圆弧,两者的区别就是是否使用了中心点,结果如下:
相比于使用椭圆,我们还是使用正圆比较多的,使用正圆展示一下效果:
RectF rectF= new RectF(100,100,800,400);
//绘制背景矩形
mPaint.setColor(Color.GRAY);
canvas.drawRect(rectF,mPaint);
//绘制圆弧
mPaint.setColor(Color.BLUE);
canvas.drawArc(rectF,0,90,false,mPaint);
//-----------------------------------------------------
RectF rectF2= new RectF(100,600,800,900);
//绘制背景矩形
mPaint.setColor(Color.GRAY);
canvas.drawRect(rectF2,mPaint);
//绘制圆弧
mPaint.setColor(Color.BLUE);
canvas.drawArc(rectF2,0,90,true,mPaint);
简要介绍Paint###
看了上面这么多,相信有一部分人会产生一个疑问,如果我想绘制一个圆,只要边不要里面的颜色怎么办?
很简单,绘制的基本形状由Canvas确定,但绘制出来的颜色,具体效果则由Paint确定。
mPaint.setStyle(Paint.Style.FILL);//设置画笔模式为填充
为了展示方便,容易看出效果,之前使用的模式一直为填充模式,实际上画笔有三种模式,如下:
STROKE //描边
FILL //填充
FILL_AND_STROKE //描边加填充
为了区分三者效果我们做如下实验:
Paint paint = new Paint();
paint.setColor(Color.BLUE);
paint.setStrokeWidth(40);
//描边
paint.setStyle(Paint.Style.STROKE);
canvas.drawCircle(200,200,100,paint);
//填充
paint.setStyle(Paint.Style.FILL);
canvas.drawCircle(200,500,100,paint);
//描边加填充
paint.setStyle(Paint.Style.FILL_AND_STROKE);
canvas.drawCircle(200,800,100,paint);