010-Android自定义View(5):画布Canvas详解(图文)

765 阅读5分钟

1.简介

Android系统提供Canvas、Paint 、Path三剑客用于绘制View图形。

如果将自定义View的绘制看作美术课绘画作业的话,

Canvas可视为画板上的空白画布,

Paint可视为画笔,

Path可视为绘画者的执笔路径。

其他坐标系等基础,可参考阅读:自定义View(1):基础

2.Canvas 的常用功能

方法功能
drawColor()设置画布颜色
drawCircle()绘制圆形
drawRect()绘制矩形
drawRoundRect()绘制带圆角的矩形
drawArc()绘制扇形 or 弧线
drawPoint()绘制点
drawPoints()绘制多个点
drawLine()绘制线
drawLines()绘制多条线
drawOval绘制椭圆
drawPath()按预设画笔路径,绘制 对应得图形
drawBitmap()在指定位置,绘制Bitmap对象
drawText()绘制文字
clipPath()根据自定义图形裁剪
clipRect()按矩形裁剪

3. 使用

3.1 drawColor() & drawCircle()

package com.cupster.base_super_resource;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.View;

import androidx.annotation.Nullable;

public class CanvasView extends View {

    Paint mPaint;
    Path mPath ;

    private void  initSetting(){
        mPaint = new Paint();
        mPath = new Path();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // 0. onDraw可能多次调用,每次绘制前都先复原paint&path
        mPaint.reset();
        mPath.reset();
        //1. 设置画布底色
//        canvas.drawColor(Color.RED);
//        canvas.drawColor(getResources().getColor(R.color.colorAccent));//使用xml定义的全局颜色
        canvas.drawColor(Color.parseColor("#e5f7ff"));//使用自定义颜色
//        canvas.drawRGB(255 ,0 ,0 );//rgb
//        canvas.drawARGB(127 ,255 ,0 ,0 );//argb
        //2. 绘制圆
        mPaint.setColor(Color.parseColor("#ff8696"));
        // 参数1 圆心x ; 参数2 圆心y ; 参数3 半径r ;
        canvas.drawCircle(200 ,200,120 ,mPaint);//java代码中直接使用的绘制单位是px,xml中使用的是dp

    }

    public CanvasView(Context context) {
        super(context);
        initSetting();
    }

    public CanvasView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        initSetting();
    }

    public CanvasView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initSetting();
    }

    public CanvasView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        initSetting();
    }
}

布局文件中使用

 <com.cupster.base_super_resource.CanvasView
            android:layout_width="200dp"
            android:layout_height="200dp"/>

3.2 DrawRect()

public class CanvasView extends View {

    Paint mPaint;
    Path mPath ;

    private void  initSetting(){
        mPaint = new Paint();
        mPath = new Path();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // 0. onDraw可能多次调用,每次绘制前都先复原paint&path
        mPaint.reset();
        mPath.reset();
        canvas.drawColor(Color.parseColor("#e5f7ff"));//使用自定义颜色
        //3. 绘制矩形
        mPaint.setColor(Color.parseColor("#ff8696"));
        //参数1:矩形【左】上角坐标x;参数2:矩形【左】上角坐标y; 参数3:矩形【右】下角坐标x ;参数4:矩形【右】下角坐标y
        canvas.drawRect(50 ,50 ,150 ,250 ,mPaint);
//        canvas.drawRect(new Rect(50 ,50 ,250 ,250 ),mPaint);//效果同上  
   //4. 绘制圆角矩形
//        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
//            canvas.drawRoundRect(100, 100, 350, 220, 50, 50, mPaint);
//        }      
  }
    public CanvasView(Context context) {
        super(context);
        initSetting();
    }
    public CanvasView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        initSetting();
    }

3.3 drawPoint() & drawPoints()

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // 0. onDraw可能多次调用,每次绘制前都先复原paint&path
        mPaint.reset();
        mPath.reset();
        canvas.drawColor(Color.parseColor("#e5f7ff"));//使用自定义颜色
        mPaint.setColor(Color.parseColor("#ff8696"));
        //. 绘制原点:点形状 大小由 paint决定
        mPaint.setStrokeWidth(20);//画笔宽度
        mPaint.setAntiAlias(true);//抗锯齿效果
        mPaint.setStyle(Paint.Style.STROKE);//描边
        mPaint.setStrokeCap(Paint.Cap.ROUND);//设置线头的模式
        canvas.drawPoint(  80 ,80,mPaint);//圆心坐标x,y
        //绘制多个圆点
//        float[] points = {10, 10, 35, 35, 30, 80, 80, 30, 80, 80, 120, 60};
//        canvas.drawPoints(points , 2 ,points.length-2 ,mPaint);//画部分点:p1:点集合,两个一组;p2:跳过几个集合参数;p3:使用多少个集合参数;p4:画笔
//        canvas.drawPoints(points ,mPaint);//全画
    }

3.4 drawOval()

   @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // 0. onDraw可能多次调用,每次绘制前都先复原paint&path
        mPaint.reset();
        mPath.reset();
        canvas.drawColor(Color.parseColor("#e5f7ff"));//使用自定义颜色
        mPaint.setColor(Color.parseColor("#ff8696"));
          //6. 绘制椭圆
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            //参数1:椭圆对应矩形【左】上角坐标x;参数2:椭圆对应矩形【左】上角坐标y; 参数3:椭圆对应矩形【右】下角坐标x ;参数4:椭圆对应矩形【右】下角坐标y
            canvas.drawOval(30,30 ,220 ,120,mPaint);
        }

3.5 drawLine() & drawLines()

@Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // 0. onDraw可能多次调用,每次绘制前都先复原paint&path
        mPaint.reset();
        mPath.reset();
 canvas.drawColor(Color.parseColor("#e5f7ff"));//使用自定义颜色
       mPaint.setColor(Color.parseColor("#ff8696"));
 //7. 画线

        mPaint.setStrokeWidth(6);
        //4个参数值对应的是两端点的坐标
        //canvas.drawLine(30,30,120,120,mPaint);
        float[] points = {10, 10, 35, 35, 35, 35, 80, 30, 80, 30, 120, 60};
//        canvas.drawLines(points ,4 ,points.length -4 ,mPaint);
        canvas.drawLines(points ,mPaint);

3.6 绘制弧线 & 扇形

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mPaint.reset();
        mPath.reset();
        canvas.drawColor(Color.parseColor("#e5f7ff"));
        mPaint.setColor(Color.parseColor("#000000"));
        //8. 画弧线/扇形
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            //前4个参数: 所依据的椭圆(圆)对应的矩形--的 左上角顶点坐标 & 右下角顶点坐标
            //第5个参数 startAngle:起始角度,x轴方向为0度,【特殊】【顺时针为正角度】
            //第6个参数 sweepAngle:扫过的角度,【特殊】【顺时针为正角度】
            //第7个参数 useCenter:是否连接到圆心,true对应连接-扇形 ,false对应不连-弧线
            canvas.drawArc(30, 30, 200, 200, -90, 90, true, mPaint); // 绘制扇形
            mPaint.setStyle(Paint.Style.STROKE);//画弧线需设置描边、不填充
            canvas.drawArc(30, 30, 200, 200, 90, 90, false, mPaint); // 绘制弧线
        }
        }

3.7 绘制path

  @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mPaint.reset();
        mPath.reset();
        //画坐标轴
        mPaint.setColor(Color.parseColor("#101010"));
        mPaint.setStyle(Paint.Style.STROKE);
        mPath.moveTo(120, 120);//y轴顶点(120,120)
        mPath.rLineTo(0, 200);//y轴方向 path移动量
        mPath.rLineTo(200, 0);//x轴方向 path移动量
        canvas.drawPath(mPath, mPaint);//绘制
}

3.8 裁剪canvas.clipXxx & canvas.clipOutXxx

   canvas.save();
        canvas.clipRect(0,0,128,128);//裁剪 显示区域
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_fangzi);
        canvas.drawBitmap(bitmap
                ,64 ,64//原bitmap绘制起点坐标
                ,mPaint);
        canvas.restore();
 canvas.save();
        canvas.clipOutRect(0,0,128,128);//裁剪 显示区域
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_fangzi);
        canvas.drawBitmap(bitmap
                ,64 ,64//原bitmap绘制起点坐标
                ,mPaint);
        canvas.restore();

3.9 canvas变换

 canvas.save();
//        canvas.rotate(15 );//绕 (0,0)
        canvas.rotate(-90 ,130,130);// 绕指定点 【特殊】【顺时针为正值角度】
        canvas.translate( -20 ,0);
        canvas.scale(1.5f ,1.0f , 130 ,130 );//x缩放倍数 y缩放倍数 ,缩放原点x ,缩放原点y
        canvas.skew( 0.0f ,0.5f);//错切  倾斜值
        canvas.drawBitmap(BitmapFactory.decodeResource(getResources() ,R.mipmap.ic_fangzi)
                ,130 ,130//绘制起点坐标
                ,mPaint);
        canvas.restore();

3.10 matrix自定义变换

 //1.创建Matrix对象
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_fangzi);

        Matrix matrix = new Matrix();
        matrix.reset();
        //2.几何变换
        matrix.postTranslate(0,10);
        matrix.postRotate(45,130,130);
        matrix.postScale(1.3f,1.3f,130,130);
        matrix.postSkew(0,0.3f);
        canvas.save();
        //3.把几何变换应用到Canvas中
        canvas.concat(matrix);
        canvas.drawBitmap(bitmap,130,130,mPaint);
        canvas.restore();