一.简介
Canvas 美[ˈkænvəs] 画布
Canvas绘图有三个基本要素:Canvas、绘图坐标系以及Paint。
- Canvas是画布,我们通过Canvas的各种drawXXX方法将图形绘制到Canvas上面,在drawXXX方法中我们需要传入要绘制的图形的坐标形状,还要传入一个画笔Paint。
- drawXXX方法以及传入其中的坐标决定了要绘制的图形的形状,比如drawCircle方法,用来绘制圆形,需要我们传入圆心的x和y坐标,以及圆的半径。
- drawXXX方法中传入的画笔Paint决定了绘制的图形的一些外观,比如是绘制的图形的颜色,再比如是绘制圆面还是圆的轮廓线等。
- Canvas的drawXXX方法中传入的各种坐标指的都是绘图坐标系中的坐标。在初始状况下,绘图坐标系的坐标原点在View的左上角。
 但绘图坐标系可以改变,例如translate方法,可以平移坐标系。且坐标系的位移是基于当前位置移动,而不是每次基于屏幕左上角的(0,0)点移动。
二.Canvas的常用操作速查表
| 操作类型 | 相关API | 备注 | 
|---|---|---|
| 绘制颜色 | drawColor, drawRGB, drawARGB | 使用单一颜色填充整个画布 | 
| 绘制基本形状 | drawPoint, drawPoints, drawLine, drawLines, drawRect, drawRoundRect, drawOval, drawCircle, drawArc | 依次为 点、线、矩形、圆角矩形、椭圆、圆、圆弧 | 
| 绘制图片 | drawBitmap, drawPicture | 绘制位图和图片 | 
| 绘制文本 | drawText, drawPosText, drawTextOnPath | 依次为 绘制文字、绘制文字时指定每个文字位置、根据路径绘制文字 | 
| 绘制路径 | drawPath | 绘制路径,绘制贝塞尔曲线时也需要用到该函数 | 
| 顶点操作 | drawVertices, drawBitmapMesh | 通过对顶点操作可以使图像形变,drawVertices直接对画布作用、 drawBitmapMesh只对绘制的Bitmap作用 | 
| 画布剪裁 | clipPath, clipRect | 设置画布的显示区域 | 
| 画布快照 | save, restore, saveLayerXxx, restoreToCount, getSaveCount | 依次为 保存当前状态、 回滚到上一次保存的状态、 保存图层状态、 回滚到指定状态、 获取保存次数 | 
| 画布变换 | translate, scale, rotate, skew | 依次为 位移、缩放、 旋转、错切 | 
| Matrix(矩阵) | getMatrix, setMatrix, concat | 实际画布的位移,缩放等操作的都是图像矩阵Matrix,只不过Matrix比较难以理解和使用,故封装了一些常用的方法。 | 
三.实战
绘制颜色 drawARGB:
绘制颜色是填充整个画布,常用于绘制底色。
- 新建CanvasView类继承View
- 重写onDraw
public class CanvasView extends View {
    //在代码中定义和使用时用到的
    public CanvasView(Context context) {
        super(context);
    }
    //在xml中定义我们的自定义属性时用到
    public CanvasView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    //在View中画出我们需要的内容
    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawARGB(255, 139, 197, 186);
    }
}
绘制画布
绘制点 drawPoint:
- 在构造函数中初始化画笔
- 重写onDraw
public class CanvasView extends View {
    private Paint mPaint;
    //在代码中定义和使用时用到的
    public CanvasView(Context context) {
        super(context);
        init();
    }
    //在xml中定义我们的自定义属性时用到
    public CanvasView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }
    //在构造函数中初始化画笔
    private void init() {
        mPaint = new Paint();
        mPaint.setColor(Color.BLACK);       //设置画笔颜色
        mPaint.setStyle(Paint.Style.FILL);  //设置画笔模式为填充
        mPaint.setStrokeWidth(10f);         //设置画笔宽度为10px
    }
    //在View中画出我们需要的内容
    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawPoint(100, 100, mPaint);     //在坐标(100,100)位置绘制一个点
        canvas.drawPoints(new float[]{          //绘制一组点,坐标位置由float数组指定
                200, 200,
                300, 400,
                400, 500
        }, mPaint);
    }
}
绘制点
绘制直线 drawLine:
protected void onDraw(Canvas canvas) {
        mPaint.setColor(Color.GREEN);// 设置绿色
        canvas.drawLine(60, 40, 100, 40, mPaint);// 画线
        canvas.drawLine(110, 40, 190, 80, mPaint);// 斜线
        canvas.drawLines(new float[]{               // 绘制一组线 每四数字(两个点的坐标)确定一条线
                100,200,200,200,
                100,300,200,300
        },mPaint);
    }
绘制直线
绘制矩形 drawRect:
确定确定一个矩形最少需要四个数据,就是对角线的两个点的坐标值,这里一般采用左上角和右下角的两个点的坐标。
protected void onDraw(Canvas canvas) {
        //取得画布的宽高
        int canvasWidth = canvas.getWidth();
        int canvasHeight = canvas.getHeight();
        //设置画笔的填充色是蓝色
        mPaint.setColor(Color.BLUE);
        int left1 = 10;
        int top1 = 10;
        int right1 = canvasWidth / 3;
        int bottom1 = canvasHeight /3;
        canvas.drawRect(left1, top1, right1, bottom1, mPaint);
        //修改画笔颜色
        mPaint.setColor(Color.RED);
        int left2 = canvasWidth / 3 * 2;
        int top2 = 10;
        int right2 = canvasWidth - 10;
        int bottom2 = canvasHeight / 3;
        canvas.drawRect(left2, top2, right2, bottom2, mPaint);
    }- 简单画了下法国国旗

绘制矩形
绘制圆角矩形 drawRoundRect:
protected void onDraw(Canvas canvas) {
        mPaint.setColor(0xff8bc5ba);//A:ff,R:8b,G:c5,B:ba
        RectF rectF = new RectF(10,10,300,150);
        //这里的圆弧是椭圆的圆弧,所以要设置椭圆的两个半径
        canvas.drawRoundRect(rectF,10,10,mPaint);
    }
rx,ry

绘制圆角矩形
绘制圆、圆环和椭圆 drawCircle、drawOval:
protected void onDraw(Canvas canvas) {
        mPaint.setColor(0xff8bc5ba);
        mPaint.setAntiAlias(true);  //设置画笔为抗锯齿模式,不然画出来太丑了
        mPaint.setStyle(Paint.Style.FILL);//默认绘图为填充模式
        int canvasWidth = canvas.getWidth();
        int canvasHeight = canvas.getHeight();
        int halfCanvasWidth = canvasWidth / 2;
        int R = canvasHeight / 9;
        // 绘制一个矩形的内切椭圆
        RectF rectF = new RectF(100, 10, 370, 150);
        canvas.drawOval(rectF, mPaint);
        // 绘制一个圆心坐标在(halfCanvasWidth,250),半径为R 的圆
        canvas.drawCircle(halfCanvasWidth, 250, R, mPaint);
        //通过绘制两个圆形成圆环
        //1. 首先绘制大圆
        canvas.drawCircle(halfCanvasWidth, 450, R, mPaint);
        //2. 然后绘制小圆,让小圆覆盖大圆,形成圆环效果
        int r = (int) (R * 0.75);
        mPaint.setColor(0xffffffff);//将画笔设置为白色,画小圆
        canvas.drawCircle(halfCanvasWidth, 450, r, mPaint);
        //通过画笔的描边绘图模式绘制圆环
        mPaint.setColor(0xff8bc5ba);//设置颜色
        mPaint.setStyle(Paint.Style.STROKE);//绘图为描边模式
        float strokeWidth = (float) (R * 0.25); //设置线条宽度
        mPaint.setStrokeWidth(strokeWidth);
        canvas.drawCircle(halfCanvasWidth, 650, R, mPaint);
    }
绘制圆、圆环、椭圆
- 简要介绍Paint的模式- STROKE 描边,把边给填充颜色
- FILL 填充,填充边中的内容
- FILL_AND_STROKE 描边加填充,就是把上面两个合起来
 
绘制圆弧 drawArc:
Canvas中提供了drawArc方法用于绘制弧,这里的弧指两种:弧面和弧线,弧面即用弧围成的填充面,弧线即为弧面的轮廓线。
public void drawArc(@NonNull RectF oval, float startAngle, float sweepAngle, boolean useCenter, @NonNull Paint paint){}- oval是RecF类型的对象,其定义了椭圆的形状。
- startAngle指的是绘制的起始角度,如果传入的startAngle小于0或者大于等于360,那么用startAngle对360进行取模后作为起始绘制角度。
- sweepAngle指的是从startAngle开始沿着钟表的顺时针方向旋转扫过的角度。如果sweepAngle大于等于360,那么会绘制完整的椭圆弧。如果sweepAngle小于0,那么会用sweepAngle对360进行取模后作为扫过的角度。
-  useCenter是个boolean值,如果为true,表示在绘制完弧之后,用椭圆的中心点连接弧上的起点和终点以闭合弧;如果值为false,表示在绘制完弧之后,弧的起点和终点直接连接,不经过椭圆的中心点。 protected void onDraw(Canvas canvas) { int canvasWidth = canvas.getWidth(); int canvasHeight = canvas.getHeight(); //把画布分成五份 float ovalHeight = canvasHeight / 5; float left = 10 ; float top = 0; float right = canvasWidth - left; float bottom= ovalHeight; RectF rectF = new RectF(left, top, right, bottom); mPaint.setAntiAlias(true); //抗锯齿 mPaint.setStrokeWidth(5);//设置线宽 mPaint.setColor(0xff8bc5ba);//设置颜色 mPaint.setStyle(Paint.Style.FILL);//默认设置画笔为填充模式 //绘制用drawArc绘制完整的椭圆 canvas.drawArc(rectF, 0, 360, true, mPaint); //绘制椭圆的四分之一,起点是0度,到90度 canvas.translate(0, ovalHeight ); //绘图坐标系平移操作,x轴移动0,y轴移动五分之一个画布长度 canvas.drawArc(rectF, 0, 90, true, mPaint); //绘制椭圆的四分之一,将useCenter设置为false canvas.translate(0, ovalHeight ); canvas.drawArc(rectF, 0, 90, false, mPaint); //绘制椭圆的四分之一,只绘制轮廓线 mPaint.setStyle(Paint.Style.STROKE);//设置画笔为描边模式 canvas.translate(0, ovalHeight ); canvas.drawArc(rectF, 0, 90, true, mPaint); //绘制带有轮廓线的椭圆的四分之一 //1. 先绘制椭圆的填充部分 mPaint.setStyle(Paint.Style.FILL);//设置画笔为填充模式 canvas.translate(0, ovalHeight ); canvas.drawArc(rectF, 0, 90, true, mPaint); //2. 再绘制椭圆的轮廓线部分 mPaint.setStyle(Paint.Style.STROKE);//设置画笔为线条模式 mPaint.setColor(0xff0000ff);//设置轮廓线条为蓝色 canvas.drawArc(rectF, 0, 90, true, mPaint); }

绘制圆弧
自定义饼图:
学了那么大堆基础终于可以画个能用的图了

自定义饼图
protected void onDraw(Canvas canvas) {
        RectF rectF = new RectF(100, 100, 400, 400);
        mPaint.setAntiAlias(true); //抗锯齿
        mPaint.setStrokeWidth(5);//设置线宽
        mPaint.setColor(0xFFCCFF00);//设置颜色
        mPaint.setStyle(Paint.Style.FILL);//默认设置画笔为填充模式
        canvas.drawArc(rectF, 0, 110, true, mPaint);
        mPaint.setColor(0xff8bc5ba);//设置颜色
        canvas.drawArc(rectF, 110, 50, true, mPaint);
        mPaint.setColor( 0xFF800000);//设置颜色
        canvas.drawArc(rectF, 160, 80, true, mPaint);
        mPaint.setColor(0xFFFF8C69);//设置颜色
        canvas.drawArc(rectF, 240, 120, true, mPaint);
    }这里是 项目地址
参考
http://blog.csdn.net/iispring/article/details/49770651
https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B02%5DCanvas_BasicGraphics.md
来自:http://www.jianshu.com/p/282958cdbf25
 
 























