Android绘图系列(四)——Canvas操作

来源:互联网 发布:中欧基金 知乎 编辑:程序博客网 时间:2024/06/05 12:51

这个系列主要是介绍下Android自定义View和Android绘图机制,自己能力有限,如果在介绍过程中有什么错误,欢迎指正

一、平移(translate)

translate函数其实实现的相当于平移坐标系,即平移坐标系的原点的位置

void translate(float dx, float dy)

参数说明:
float dx:水平方向平移的距离,正数指向正方向(向右)平移的量,负数为向负方向(向左)平移的量
flaot dy:垂直方向平移的距离,正数指向正方向(向下)平移的量,负数为向负方向(向上)平移的量

请注意,位移是基于当前位置移动,而不是每次基于屏幕左上角的(0,0)点移动

 @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        Paint paint = new Paint();        paint.setColor(Color.GREEN);        paint.setStyle(Paint.Style.FILL);        //未平移        Rect rect1 = new Rect(0,0,400,220);        canvas.drawRect(rect1, paint);        //平移        paint.setColor(Color.RED);        canvas.translate(500,300);        Rect rect2 = new Rect(0,0,400,220);        canvas.drawRect(rect2, paint);    }

效果图
这里写图片描述

注意:两次的坐标原点不一样


二.旋转(rotate)

旋转提供了两种方法:

  public void rotate (float degrees)  public final void rotate (float degrees, float px, float py)

第一个构造函数直接输入旋转的度数,正数是顺时针旋转,负数指逆时针旋转,它的旋转中心点是原点(0,0)
第二个构造函数除了度数以外,还可以指定旋转的中心点坐标(px,py)

注意:默认的旋转中心依旧是坐标原点

  • 不指定旋转中心
         //不指定旋转中心        canvas.rotate(30);        paint.setColor(Color.RED);        Rect rect2 = new Rect(0,0,400,220);        canvas.drawRect(rect2, paint);

效果图
这里写图片描述

-指定旋转中心

        //指定旋转中心        canvas.rotate(180,200,200);        paint.setColor(Color.RED);        Rect rect2 = new Rect(0,0,400,220);        canvas.drawRect(rect2, paint);

这里写图片描述

注意:旋转是可叠加的

     canvas.rotate(100);     canvas.rotate(50);

调用两次旋转,则实际的旋转角度为100+50=150度。


三.缩放(scale)

缩放提供了两个方法,如下:

 public void scale (float sx, float sy) public final void scale (float sx, float sy, float px, float py)

这两个方法中前两个参数是相同的分别为x轴和y轴的缩放比例。而第二种方法比前一种多了两个参数,用来控制缩放中心位置的。

缩放比例(sx,sy)取值范围详解:

取值范围(n) 说明 [-∞, -1) 先根据缩放中心放大n倍,再根据中心轴进行翻转 -1 根据缩放中心轴进行翻转 (-1, 0) 先根据缩放中心缩小到n,再根据中心轴进行翻转 0 不会显示,若sx为0,则宽度为0,不会显示,sy同理 (0, 1) 根据缩放中心缩小到n 1 没有变化 (1, +∞) 根据缩放中心放大n倍

注意:缩放的中心默认为坐标原点,而缩放中心轴就是坐标轴

      @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        Paint paint=new Paint();        paint.setColor(Color.GREEN);        paint.setStyle(Paint.Style.FILL);        RectF rectF=new RectF(0,0,400,400);        canvas.drawRect(rectF,paint);        //未控制缩放点        canvas.scale(0.5f,0.5f);        paint.setColor(Color.RED);        canvas.drawRect(rectF,paint);    }

这里写图片描述

接下来我们使用第二种方法让缩放中心位置稍微改变一下,如下:

        // 将坐标系原点移动到画布正中心       //控制缩放点        //缩放中心向右偏移了200个单位        canvas.scale(0.5f,0.5f,200,0);        paint.setColor(Color.RED);        canvas.drawRect(rectF,paint);

这里写图片描述

前面两个示例缩放的数值都是正数,按照表格中的说明,当缩放比例为负数的时候会根据缩放中心轴进行翻转,下面我们就来实验一下:

       //指定负数缩放比例        canvas.scale(-0.5f,-0.5f);//        paint.setColor(Color.RED);        canvas.drawRect(rectF,paint);

这里写图片描述
由于本次未对缩放中心进行偏移,所有默认的缩放中心就是坐标原点,中心轴就是x轴和y轴。

本次缩放可以看做是先根据缩放中心(坐标原点)缩放到原来的0.5倍,然后分别按照x轴和y轴进行翻转。

        //指定负数缩放比例        canvas.scale(-0.5f,-0.5f,200,0);//        paint.setColor(Color.RED);        canvas.drawRect(rectF,paint);

这里写图片描述

PS:和位移(translate)一样,缩放也是可以叠加的。

   canvas.scale(0.5f,0.5f);   canvas.scale(0.5f,0.1f);

调用两次缩放则 x轴实际缩放为0.5x0.5=0.25 y轴实际缩放为0.5x0.1=0.05

注意:下面的例子截取自网络

下面我们利用这一特性制作一个有趣的图形。

        // 将坐标系原点移动到画布正中心        canvas.translate(mWidth / 2, mHeight / 2);        RectF rect = new RectF(-400,-400,400,400);   // 矩形区域        for (int i=0; i<=20; i++)        {            canvas.scale(0.9f,0.9f);            canvas.drawRect(rect,mPaint);        }


四.斜切Skew

void skew (float sx, float sy)

参数说明:
float sx:将画布在x方向上倾斜相应的角度,sx倾斜角度的tan值,
float sy:将画布在y轴方向上倾斜相应的角度,sy为倾斜角度的tan值,

注意,这里全是倾斜角度的tan值哦,比如我们打算在X轴方向上倾斜60度,tan60=根号3,小数对应1.732

变换后:

X = x + sx * yY = sy * x + y
@Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        //skew 扭曲        Paint paint=new Paint();        paint.setColor(Color.GREEN);        paint.setStyle(Paint.Style.FILL);        Rect rect = new Rect(0,0,200,200);        canvas.drawRect(rect, paint);        canvas.skew(1,0);//X轴倾斜45度,Y轴不变        paint.setColor(Color.RED);        canvas.drawRect(rect, paint);    }

这里写图片描述


五.裁剪Clip

裁剪画布是利用Clip系列函数,通过与Rect、Path、Region取交、并、差等集合运算来获得最新的画布形状。除了调用Save、Restore函数以外,这个操作是不可逆的,一但Canvas画布被裁剪,就不能再被恢复!
Clip系列函数如下:

boolean clipPath(Path path)boolean clipPath(Path path, Region.Op op)boolean clipRect(Rect rect, Region.Op op)boolean clipRect(RectF rect, Region.Op op)boolean clipRect(int left, int top, int right, int bottom)boolean clipRect(float left, float top, float right, float bottom)boolean clipRect(RectF rect)boolean clipRect(float left, float top, float right, float bottom, Region.Op op)boolean clipRect(Rect rect)boolean clipRegion(Region region)boolean clipRegion(Region region, Region.Op op)
@Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        canvas.drawColor(Color.RED);        canvas.clipRect(new Rect(100, 100, 200, 200));        canvas.drawColor(Color.GREEN);    }

这里写图片描述


六.保存(save)和恢复(restore)

画布的操作是不可逆的,而且很多画布操作会影响后续的步骤,所以会对画布的一些状态进行保存和回滚。

相关API 简介 save 把当前的画布的状态进行保存,然后放入特定的栈中 saveLayerXxx 新建一个图层,并放入特定的栈中 restore 把栈中最顶层的画布状态取出来,并按照这个状态恢复当前的画布 restoreToCount 弹出指定位置及其以上所有的状态,并按照指定位置的状态进行恢复 getSaveCount 获取栈中内容的数量(即保存次数)

说一个状态栈的概念,这个栈可以存储画布状态和图层状态。

先进行三次save

 @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        canvas.drawColor(Color.RED);        //保存的画布大小为全屏幕大小        canvas.save();        canvas.clipRect(new Rect(100,100,800,800));        canvas.drawColor(Color.GREEN);        canvas.save();        canvas.clipRect(new Rect(100,100,600,600));        canvas.drawColor(Color.YELLOW);        canvas.save();    }

这里写图片描述


进行一次restore

 @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        canvas.drawColor(Color.RED);        //保存的画布大小为全屏幕大小        canvas.save();        canvas.clipRect(new Rect(100,100,800,800));        canvas.drawColor(Color.GREEN);        canvas.save();        canvas.clipRect(new Rect(100,100,600,600));        canvas.drawColor(Color.YELLOW);        canvas.save();        canvas.clipRect(new Rect(100,100, 400, 400));        canvas.drawColor(Color.WHITE);        canvas.restore();        canvas.drawColor(Color.BLUE);    }

这里写图片描述


进行三次restore

@Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        canvas.drawColor(Color.RED);        //保存的画布大小为全屏幕大小        canvas.save();        canvas.clipRect(new Rect(100,100,800,800));        canvas.drawColor(Color.GREEN);        canvas.save();        canvas.clipRect(new Rect(100,100,600,600));        canvas.drawColor(Color.YELLOW);        canvas.save();        canvas.clipRect(new Rect(100,100, 400, 400));        canvas.drawColor(Color.WHITE);        canvas.restore();        canvas.restore();        canvas.restore();        canvas.drawColor(Color.BLUE);    }

这里写图片描述


OK啦,这篇就到了啦。

Github地址

参考:

http://www.gcssloop.com/customview/Canvas_Convert
http://blog.csdn.net/harvic880925/article/details/39080931

0 0