分享

Android自定义View(七)Canvas学习

 印度阿三17 2019-05-21

一、介绍

Canvas之为画布,但是并不是真的直接在Canvas画,而是bitmap默认会创建一个bitmap,也可以通过构造方法或者setBitmap方法传入,像素所有的信息画在了这个bitmap上。


二、drawBitmap()

共有6个重载方法,但是其中两个参数最多的已经废弃掉了,那么就学习4个吧!

在draw方法中,有一个很牛逼的方法:drawBitmapMesh,但是一般不会用到。简单处理图片我们一般会用到Metrix,但是遇到Metrix处理不了的,记得还可以研究一下drawBitmapMesh。

    public void drawBitmap(@NonNull Bitmap bitmap, float left, float top, @Nullable Paint paint) {
        super.drawBitmap(bitmap, left, top, paint);
    }

    //使用
    canvas.drawBitmap(srcBitmap,0,0,paint);
  • bitmap 原始图片
  • left 图片的左上角的X轴坐标
  • top 图片的右上角的Y轴坐标
  • paint 画笔
    public void drawBitmap(@NonNull Bitmap bitmap, @Nullable Rect src, @NonNull Rect dst,
            @Nullable Paint paint) {
        super.drawBitmap(bitmap, src, dst, paint);
    }

    //使用
    canvas.drawBitmap(srcBitmap,new Rect(0,0,720,500), new Rect(0,0,720,500),paint);
  • src 剪切区域
  • dst view中的显示位置,可以拉伸或缩放
    public void drawBitmap(@NonNull Bitmap bitmap, @Nullable Rect src, @NonNull RectF dst,
            @Nullable Paint paint) {
        super.drawBitmap(bitmap, src, dst, paint);
    }

    //使用
    canvas.drawBitmap(srcBitmap,new Rect(0,0,720,500), new RectF(0,0,720,500),paint);
  • 与上一个重载方法基本相同,区别是dst为浮点类型
    public void drawBitmap(@NonNull Bitmap bitmap, @NonNull Matrix matrix, @Nullable Paint paint) {
        super.drawBitmap(bitmap, matrix, paint);
    }

    //使用
    Matrix matrix = new Matrix();
    matrix.setTranslate(20f,20f);
    canvas.drawBitmap(srcBitmap,matrix,paint);
  • matrix 一个3 * 3的矩阵,矩阵在后面会学习到,在这里不做仔细说明了,现在也不懂

三、drawLines

3.1 画一条直线:

    public void drawLine(float startX, float startY, float stopX, float stopY,
            @NonNull Paint paint) {
        super.drawLine(startX, startY, stopX, stopY, paint);
    }

    //使用
    canvas.drawLine(0,0,500,500,paint);
  • startX 起点X轴的坐标
  • startY 起点Y轴的坐标
  • stopX 终点X轴的坐标
  • stopY 终点Y轴的坐标
  • paint 画笔

3.2 画多条直线:

    public void drawLines(@Size(multiple = 4) @NonNull float[] pts, @NonNull Paint paint) {
        super.drawLines(pts, paint);
    }

    //使用
    canvas.drawLines(new float[]{0,0,500,500,10,0,900,200},paint);
  • pts 坐标数组,4个数值为一组,分别表示一条直线的两端坐标。源码中注解:@Size(multiple = 4) 需要是4的倍数

3.3 画多条直线

    public void drawLines(@Size(multiple = 4) @NonNull float[] pts, int offset, int count,
            @NonNull Paint paint) {
        super.drawLines(pts, offset, count, paint);
    }

    //使用
    canvas.drawLines(new float[]{0,0,500,500,10,0,900,200},4,4,paint);
  • offset 要跳过的数组中数的个数,为4,则代表数组中前4位无效
  • count 数组中有效数的数量 总共8个,跳过4个,count就为4

四、drawPoint

4.1 画一个点

    public void drawPoint(float x, float y, @NonNull Paint paint) {
        super.drawPoint(x, y, paint);
    }

    //使用
    canvas.drawPoint(100f,100f,paint);
  • x X轴的坐标
  • y Y轴的坐标

4.2 画多个点

    public void drawPoints(@Size(multiple = 2) @NonNull float[] pts, @NonNull Paint paint) {
        super.drawPoints(pts, paint);
    }

    //使用 
    canvas.drawPoints(new float[]{100f,100f,300f,200f},paint);
  • 两个点为一组,表示一个点的坐标位置;
    源码中注解:@Size(multiple = 2) 长度须是2的倍数,如果数据中有5个值,生效的只有前4个

4.3 画多个点

    public void drawPoints(@Size(multiple = 2) float[] pts, int offset, int count,
            @NonNull Paint paint) {
        super.drawPoints(pts, offset, count, paint);
    }

    //使用
    canvas.drawPoints(new float[]{100f,100f,300f,200f},2,2,paint);
  • offset 要跳过的数量,跳过的数值时无效的
  • count 数组的有效数据量

五、drawPath

5.1 moveTo、lineTo、close

moveTo指定路径的开始坐标位置,lineTo过程坐标位置,可以为多个。close路径绘制关闭,将终点与起点连接起来,绘制一个等腰三角形:

        path = new Path();
        path.moveTo(360,20);
        path.lineTo(200,220);
        path.lineTo(520,220);
        path.close();//关闭
        canvas.drawPath(path,paint);

绘制路径用到Path,首先我们先创建一个Path对象,通过moveTo指定起始坐标点,lineTo需要绘制的路径坐标。close关闭并连接终点与起点。条用drawPath进行绘制。在绘制路径时,需要将Paint的Style指定为STROKE。

5.2 quadTo

可以来绘制二阶贝塞尔曲线,也就是3个点确定一个曲线,由3个点来确定:(100,100),(200,200),(900,100)

        Path path = new Path();
        path.moveTo(100f,100f);
        float[] floats = new float[]{200f,200f,900f,100f};
        path.quadTo(200f,200f,900f,100f);
        canvas.drawPath(path,paint);
        canvas.drawPoints(floats,paint);

5.3 cubicTo

此方法与quadTo基本相同,多了一个点。也就是quadTo3个点确定一个贝塞尔曲线,而cubicTo是四个点。

        Path path = new Path();
        path.moveTo(100f,100f);
        path.cubicTo(200f,200f,400f,100f,700f,200f);
        canvas.drawPath(path,paint);

5.4 arcTo

在规定区域内绘制一个圆弧,并判断圆弧的起始点和路径的起始点是否为同一点,不同则连接

        Path path = new Path();
        path.moveTo(100f,100f);
        RectF rect = new RectF(200, 200, 400, 400);
        path.arcTo(rect,0,90);
        canvas.drawPath(path,paint);

我们一起看一下这个绘制流程:首先创建了一个路径Path,指定了起始位置,rect指的是一个矩形,arcTo会在这个矩形中根据指定的弧度绘制圆弧,0,90就是上图所示。最后并将圆弧的起始点与路径的起始点连接在一起。

5.5 rLineTo

r是Relative的缩写,相对的意思。rLineTo绘制时以path最后一个点为坐标原点(0,0),这里是(100,100);lineTo、rLineTo起始点默认是屏幕左上角的坐标系原点(0,0)!

        Path path = new Path();
        path.moveTo(100f, 100f);
        path.rLineTo(300, 200);
        canvas.drawPath(path, paint);
        canvas.drawPoint(300, 200, paint);

在绘制过程中,我们指定的终点坐标为(300,200),但实际点点坐标为(400,300)。原因是相对于起始点进行计算的,在这里起始点(100,100)就相当于是(0,0);

5.6 addArc

与arcTo方法的区别是:不会把圆弧的起始点和路径的起始点连接在一起.

        Path path = new Path();
        path.moveTo(100,100);
        path.lineTo(200,200);
        RectF rect = new RectF(300,300,500,400);
        path.addArc(rect,0,90);
        canvas.drawPath(path,paint);

5.7 addOval、drawTextOnPath 在路径上绘制文字

        Path path = new Path();
        path.moveTo(100f,100f);
        Paint textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        textPaint.setTextSize(30f);
        RectF rectF = new RectF(300,300,490,490);
        path.addOval(rectF, Path.Direction.CW);
//        path.addOval(rectF, Path.Direction.CCW);//改变闭合方向,文字会内侧且逆时针绘制
        canvas.drawPath(path,paint);
        char[] chaars = new char[]{'a','b','c','d','e'};
        canvas.drawTextOnPath(chaars,0,5,path,0f,5,textPaint);

Path.Direction.CCW 改变闭合方向,文字会内侧且逆时针绘制。

5.8 drawTextRun

        Paint textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        textPaint.setTextSize(60f);
        char[] chars = new char[]{'a', 'b', 'c', 'd', 'e'};
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            canvas.drawTextRun(chars, 0, chars.length, 0, chars.length, 100f, 100f, true, textPaint);
        }

isRtl 为true : 文字倒着绘制,此方法必须在API大于23的时候才能使用。

5.9 clipRect裁剪规则区域

        Rect rect = new Rect(0,0,300,300);
        canvas.drawColor(Color.BLUE); //绘制背景色
        canvas.clipRect(rect); //剪切画布
        canvas.drawColor(Color.RED); //剪切后的画布背景色
        canvas.drawRect(100,100,400,400,new Paint(Paint.ANTI_ALIAS_FLAG)); //看一下剪切的画布是否生效

我们指定裁剪画布的区域是(0,0,300,300),也就是后红色的区域为我们裁剪后的画布。为了验证裁剪画布是否生效,我们又画了一个矩形,这个矩形是(100,100,400,400),很明显没有绘制完整,因为矩形绘制的区域超出了现有画布的区域。

5.10 rotate画布旋转

    public void rotate(float degrees) {
        if (degrees == 0.0f) return;
        nRotate(mNativeCanvasWrapper, degrees);
    }

    canvas.rotate(30); //画布旋转
  • degrees 旋转度数

5.11 op方法

这个方法的作用是:处理画布多次裁剪。

        Rect rect1 = new Rect(100,100,300,300);
        Rect rect2 = new Rect(200,200,400,400);
        canvas.drawColor(Color.BLUE);//背景色  蓝色
        canvas.save(); //保存画布
        canvas.clipRect(rect1); //绘制第一块区域
        canvas.clipRect(rect2, Region.Op.XOR); //绘制第二块区域
        //截取后有效区域绘制红色
        canvas.drawColor(Color.RED);
        canvas.restore();
        //绘制辅助区域
        canvas.drawRect(100,100,300,300,paint);
        canvas.drawRect(200,200,400,400,paint);

首先呢,创建两个矩形,用于裁剪画布。指定画布的背景色为蓝色,使用clipRect裁剪规则画布,这里指定的op为XOR,取两次绘制的非交集部分。

Region.Op.DIFFERENCE 取第一次剪切的非交集部分:

Region.Op.INTERSECT 取两次剪切的交集部分:

Region.Op.REPLACE 第二次代替第一次剪切:

Region.Op.UNION 两次剪切的和:

Region.Op.REVERSE_DIFFERENCE 第二次剪切的非交集部分 :

5.12 clipPath 裁剪不规则画布

        Path path = new Path();
        path.addCircle(100,100,100, Path.Direction.CW); //裁剪不规则图形
        canvas.drawColor(Color.BLUE);
        canvas.clipPath(path);
        canvas.drawColor(Color.RED);
        //绘制辅助圆
        canvas.drawCircle(100,100,100,paint);

用Path指定了一个圆形。

5.13 save restore

        Rect path1 = new Rect(100,100,300,300);
        Rect path2 = new Rect(150,150,200,200);
        canvas.translate(500,200); //画布平移
        canvas.drawColor(Color.BLUE);
        canvas.clipRect(path1);
        canvas.drawColor(Color.RED);
        canvas.save(); //保存当前层
        canvas.rotate(10); //旋转
        canvas.clipRect(path2);
        canvas.drawColor(Color.GREEN);
        canvas.restore(); //把图层恢复到最后一次save()前的状态
  • save 保存当前层
  • restore 把图层恢复到最后一次save()前的状态
  • 关于保存图层,还有一个更加强大的saveLayer(),这个方法就等用到时,再进行学习

5.14 scale缩放

        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.img2);
        canvas.scale(0.2f,0.2f); //缩放的值为 0 - 1f 1代表不缩放 默认的缩放中心是(0,0)
        canvas.drawBitmap(bitmap, 0, 0, paint);

canvas.scale(0.2f, 0.2f, 360, 0); //指定缩放中心 (360,0)

5.15 skew 错切

        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.img2);
        canvas.skew(0.3f,0);
        canvas.drawBitmap(bitmap, 0, 0, paint);
  • sx 将画布在x方向上倾斜相应的角度,sx倾斜角度的tan值,其实就是将y逆时针旋转相应的角度
  • sy 将画布在y方向上倾斜相应的角度,sx倾斜角度的tan值,其实就是将x顺时针旋转相应的角度
来源:http://www./content-4-201651.html

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多