(十)Canvas 的基本使用

来源:互联网 发布:cad中网络接口怎么画 编辑:程序博客网 时间:2024/06/05 17:04

版权声明:本文为博主原创文章,未经博主允许不得转载。

本文纯个人学习笔记,由于水平有限,难免有所出错,有发现的可以交流一下。

一、概述

Canvas 我们经常把它理解为画板,但是,实际上 Canvas 是一个封装类,它包含了四个东西:

1、画板:用来保存像素的bitmap

2、画布或者画纸: Canvas 在 Bitmap 上进行绘制操作 —- (Layer—saveLayer操作时,新建一个透明的画布图层)

3、绘制的东西

4、绘制的画笔 Paint

二、Canvas 的基本方法

1.画直线

这里写图片描述

  canvas.drawLine(0, 0, 100, 100, paint);

drawLine(float startX, float startY, float stopX, float stopY, Paint paint)
startX: 起始点 x 坐标
startY :起始点 y坐标
stopX: 结束点 x 坐标
stopY :结束点 y坐标
paint :画笔

2.画多条直线

这里写图片描述

    float []pts = {0,0,100,100,200,200,300,300};    canvas.drawLines(pts, paint);

drawLines(float[] pts, Paint paint)
pts : 直线的端点数组,每 4 个点为一条直线

drawLines(float[] pts, int offset, int count, Paint paint)
pts : 直线的端点数组,每 4 个点为一条直线
offset : 跳过的数据个数,跳过的数据不参与直线绘制
count : 实际参与绘制的数据个数

3.画点

这里写图片描述

    canvas.drawPoint(50, 50, paint);

drawPoint(float x, float y, Paint paint)
x : 点的 x 坐标
y : 点的 y 坐标

4.画多个点

这里写图片描述

    float []pts = {0,0,100,100,200,200,300,300};       canvas.drawPoints(pts, paint);

drawPoints(float[] pts, Paint paint)
pts : 点的坐标数组,每 2个点为一个点

drawPoints(float[] pts, int offset, int count, Paint paint)
pts : 点的坐标数组,每 2个点为一个点
offset : 跳过的数据个数,跳过的数据不参与点绘制
count : 实际参与绘制的数据个数

5.画矩形

这里写图片描述

    RectF r = new RectF(100, 100, 400, 500);    canvas.drawRect(r, paint);
    canvas.drawRectdrawRect(100, 100, 400, 500, paint);

drawRect(RectF rect, Paint paint)
rect : 矩形区域

drawRect(Rect r, Paint paint)
r : 矩形区域

drawRect(float left, float top, float right, float bottom, Paint paint)
left : 左边的 x 坐标
top :上边的 y 坐标
right : 右边的 x 坐标
bottom : 底边的 y 坐标

注:RectF 和 Rect 主要区别是精度,RectF 使用的是 float, Rect 使用的是 int。

6.画圆角矩形

这里写图片描述

    RectF r = new RectF(100, 100, 400, 500);    canvas.drawRoundRect(r, 30, 30, paint);
    canvas.drawRoundRect(100, 100, 400, 500, 30, 30, paint);

drawRoundRect(RectF rect, float rx, float ry, Paint paint)
rect : 矩形区域
rx:x方向上的圆角半径。
ry:y方向上的圆角半径。

drawRoundRect(float left, float top, float right, float bottom, float rx, float ry, Paint paint)
left : 左边的 x 坐标
top :上边的 y 坐标
right : 右边的 x 坐标
bottom : 底边的 y 坐标
rx:x方向上的圆角半径。
ry:y方向上的圆角半径。

7.画圆

这里写图片描述

    canvas.drawCircle(300, 300, 200, paint);

drawCircle(float cx, float cy, float radius, Paint paint)
cx : 圆心的x坐标
cy : 圆心的y坐标
radius : 圆的半径

8.画椭圆

这里写图片描述

    RectF r = new RectF(100, 100, 400, 500);    canvas.drawOval(r, paint);
    canvas.drawOval(100, 100, 400, 500, 30, 30, paint);

drawOval(RectF oval, Paint paint)
oval : 外切矩形区域

drawOval(float left, float top, float right, float bottom, Paint paint)
left : 外切矩形左边的 x 坐标
top :外切矩形上边的 y 坐标
right : 外切矩形右边的 x 坐标
bottom :外切矩形 底边的 y 坐标

9.画圆弧

这里写图片描述

    RectF r = new RectF(100, 100, 400, 500);    canvas.drawArc(r, 0, 90, true, paint);
    canvas.drawArc(100, 100, 400, 500, 0, 90, true, paint);

drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint)
oval : 圆弧所在椭圆外切矩形
startAngle : 圆弧的起始角度(0 为 x轴正方向)
sweepAngle : 圆弧的角度
useCenter:是否显示半径连线,true表示显示圆弧与圆心的半径连线,false表示不显示

drawArc(float left, float top, float right, float bottom, float startAngle, float sweepAngle, boolean useCenter, Paint paint)
left : 圆弧所在外切矩形左边的 x 坐标
top :圆弧所在外切矩形上边的 y 坐标
right : 圆弧所在外切矩形右边的 x 坐标
bottom :圆弧所在外切矩形 底边的 y 坐标
startAngle : 圆弧的起始角度(0 为 x轴正方向)
sweepAngle : 圆弧的角度
useCenter:是否显示半径连线,true表示显示圆弧与圆心的半径连线,false表示不显示

把 useCenter 改为 false:
这里写图片描述

10.画路径

这里写图片描述

        Path path = new Path();        //画笔落笔的位置        path.moveTo(100, 100);        //移动        path.lineTo(200, 100);        path.lineTo(200, 200);        path.cubicTo(250, 200, 400, 250, 450, 400);        path.close();        canvas.drawPath(path, paint);

drawPath(Path path, Paint paint)
path : 路径

path 部分不在这边细讲。

三、Canvas 画区域

Canvas 除了画常用的形状之外,还能画 Region ,它表示的 Canvas 图层上的一块封闭的区域。由于区域是不规则的,所以在绘制的时候会被切割成多个矩形,通过迭代进行绘制。

这里写图片描述

    Paint paint = new Paint();    paint.setColor(Color.RED);    //样式必须设为 STROKE,否则看不出效果    paint.setStyle(Paint.Style.STROKE);    paint.setStrokeWidth(2);    RectF r = new RectF(100, 100, 600, 800);    Path path = new Path();    path.addOval(r, Path.Direction.CCW);    //创建一块矩形的区域    Region region = new Region(100, 100, 600, 800);    Region region1 = new Region();    //path的椭圆区域和矩形区域进行交集    region1.setPath(path, region);    //结合区域迭代器使用(得到图形里面的所有的矩形区域)    RegionIterator iterator = new RegionIterator(region1);    Rect rect = new Rect();    //通过迭代,进行区域的绘制    while (iterator.next(rect)) {        canvas.drawRect(rect, paint);    }   

区域的叠加规则

区域叠加规则枚举类 Op 的源码:

    public enum Op {        DIFFERENCE(0),        INTERSECT(1),        UNION(2),        XOR(3),        REVERSE_DIFFERENCE(4),        REPLACE(5);        Op(int nativeInt) {            this.nativeInt = nativeInt;        }        /**         * @hide         */        public final int nativeInt;    }

这里写图片描述
效果图中 A 为调用者, B 为叠加上来的区域。

op(Rect r, Op op)
r: 叠加上去的矩形
op : 叠加规则

op(int left, int top, int right, int bottom, Op op)
left : 叠加上去的矩形左边的 x 坐标
top :叠加上去的矩形上边的 y 坐标
right : 叠加上去的矩形右边的 x 坐标
bottom :叠加上去的矩形 底边的 y 坐标
op : 叠加规则

op(Region region, Op op)
region: 叠加上去的区域
op : 叠加规则

四、Canvas 坐标系

这里写图片描述

        Paint paint = new Paint();        paint.setStyle(Paint.Style.STROKE);        paint.setStrokeWidth(10);        RectF r = new RectF(0, 0, 400, 500);        paint.setColor(Color.GREEN);        canvas.drawRect(r, paint);        //平移        canvas.translate(50, 50);        paint.setColor(Color.BLUE);        canvas.drawRect(r, paint);

上方代码先绘制一个矩形,然后进行平移操作,后再次绘制一个矩形。在 translate(50, 50) 里平移的是 Canvas 的绘图坐标系,而不是 Canvas。我们可以稍微证明一下。
这里写图片描述

        Paint paint = new Paint();        paint.setStyle(Paint.Style.STROKE);        paint.setStrokeWidth(10);        RectF r = new RectF(0, 0, 400, 500);        paint.setColor(Color.GREEN);        canvas.drawRect(r, paint);        //平移        canvas.translate(50, 50);        canvas.drawColor(Color.YELLOW);        paint.setColor(Color.BLUE);        canvas.drawRect(r, paint);

在平移后给画布填充颜色,发现整个屏幕都充满,说明平移的不是画布。

Canvas里面牵扯两种坐标系:Canvas 自己的坐标系、绘图坐标系。

1.Canvas 自己的坐标系

它就在View的左上角,做坐标原点往右是X轴正半轴,往下是Y轴的正半轴,有且只有一个,唯一不变。

2..Canvas 绘图坐标系

它不是唯一不变的,它与Canvas的Matrix有关系,当Matrix发生改变的时候,绘图坐标系对应的进行> > 改变。

用画直线的方法把平移前后的坐标系画出来。可以发现平移之后坐标系变了。

这里写图片描述

        RectF r = new RectF(0, 0, 400, 500);        paint.setColor(Color.GREEN);        canvas.drawRect(r, paint);        canvas.drawLine(0,0,canvas.getWidth(),0,paint);// X 轴        canvas.drawLine(0,0,0,canvas.getHeight(),paint);// Y 轴        canvas.translate(50, 50);        paint.setColor(Color.BLUE);        canvas.drawRect(r, paint);        canvas.drawLine(0,0,canvas.getWidth(),0,paint);// X 轴        canvas.drawLine(0,0,0,canvas.getHeight(),paint);// Y 轴

继续进行旋转45度。
这里写图片描述

        RectF r = new RectF(0, 0, 400, 500);        paint.setColor(Color.GREEN);        canvas.drawRect(r, paint);        canvas.drawLine(0,0,canvas.getWidth(),0,paint);// X 轴        canvas.drawLine(0,0,0,canvas.getHeight(),paint);// Y 轴        canvas.translate(50, 50);        paint.setColor(Color.BLUE);        canvas.drawRect(r, paint);        canvas.drawLine(0,0,canvas.getWidth(),0,paint);// X 轴        canvas.drawLine(0,0,0,canvas.getHeight(),paint);// Y 轴        canvas.rotate(45);        paint.setColor(Color.YELLOW);        canvas.drawLine(0,0,canvas.getWidth(),0,paint);// X 轴        canvas.drawLine(0,0,0,canvas.getHeight(),paint);// Y 轴

结论:绘制坐标的变化跟矩阵 Matrix 有关。Matrix又是通过我们设置translate、rotate、scale、skew来进行改变的

3.Canvas 绘图坐标系的重置

Canvas 绘制坐标系的变化过程是不可逆的,只能通过 save 和 restore 方法来保存和还原变化操作

这里写图片描述

    RectF r = new RectF(0, 0, 400, 500);        paint.setColor(Color.GREEN);        canvas.drawRect(r, paint);        canvas.drawLine(0,0,canvas.getWidth(),0,paint);// X 轴        canvas.drawLine(0,0,0,canvas.getHeight(),paint);// Y 轴        canvas.save();        canvas.translate(50, 50);        paint.setColor(Color.BLUE);        canvas.drawRect(r, paint);        canvas.drawLine(0,0,canvas.getWidth(),0,paint);// X 轴        canvas.drawLine(0,0,0,canvas.getHeight(),paint);// Y 轴        canvas.restore();        canvas.rotate(45);        paint.setColor(Color.YELLOW);        canvas.drawLine(0,0,canvas.getWidth(),0,paint);// X 轴        canvas.drawLine(0,0,0,canvas.getHeight(),paint);// Y 轴

在第一次变化坐标前 save,绘制坐标系后 restore, 再次进行坐标变化是从最开始的坐标系进行变化。说明第一次变化后,坐标系重置还原了。

五、Canvas的状态保存—状态栈、Layer栈

1.状态栈 – save、 restore 方法

1.只是保存和还原变换操作 Matrix 以及 Clip 剪裁,
2.可以通过 restoretoCount 直接还原到对应栈的保存状态。
3.不是真正的图层关系

2.Layer栈

1.真正的图层关系,saveLayer 的时候都会新建一个透明的图层(离屏 Bitmap-离屏缓冲),并且会将saveLayer 之前的一些 Canvas 操作延续过来
2. 后续的绘图操作都在新建的layer上面进行
3.当我们调用restore 或者 restoreToCount 时会更新到对应的图层和画布上

saveLayer 可以实现所有 save 的实现效果。save 只是在栈中保存 Matrix 以及 Clip 剪裁的变换记录,当开始绘制的时候,根据栈中保存的变换记录得出最终的绘制坐标,从而进行绘制。saveLayer 是把前面的操作保存成一个 Layer 存入栈中,再新建一个 Layer,后续绘制在新的 Layer 上进行,新绘制的 Layer 可以根据 saveLayer 的时候传的参数进行选择保存上一个 Layer 的哪些 Matrix 以及 Clip 剪裁的变换。

目前个人除了在使用 Xfermode 的时候,用 save() 方法的话,原先绘制的背景会对浑噩结果造成影响,所以要用 saveLayer()。其他地方使用暂时没有发现区别。

原创粉丝点击