美文网首页
★60.自定义控件 ★05.Canvas之画布操作

★60.自定义控件 ★05.Canvas之画布操作

作者: iDragonfly | 来源:发表于2017-06-29 00:11 被阅读0次

    简介

    画布操作 可以使绘图变得非常容易。例如:画一个从坐标原点为起点,绘制一个长度为20dp,与水平线夹角为30度的线段,可以通过以下步骤获得:

    1. 绘制一个长度为20dp的水平线。
    2. 将画布旋转30度。

    translate()——位移

    translate()是坐标系的移动,可以为图形绘制选择一个合适的坐标系。请注意,位移是基于当前位置移动,而不是每次基于屏幕左上角的(0,0)点移动,如下:

    // 省略了创建画笔的代码
    
    // 在坐标原点绘制一个黑色圆形
    mPaint.setColor(Color.BLACK);
    canvas.translate(200,200);
    canvas.drawCircle(0,0,100,mPaint);
    
    // 在坐标原点绘制一个蓝色圆形
    mPaint.setColor(Color.BLUE);
    canvas.translate(200,200);
    canvas.drawCircle(0,0,100,mPaint);
    

    scale()——缩放

    缩放方法

    public void scale (float sx, float sy);
    // 后面两个参数用来控制缩放中心位置的,缩放的中心默认为坐标原点
    public final void scale (float sx, float sy, float px, float py);
    

    缩放中心

    示例一:

    缩放的中心默认是画布坐标原点。

    // 将坐标系原点移动到画布正中心
    canvas.translate(mWidth / 2, mHeight / 2);
    
    RectF rect = new RectF(0,-400,400,0);   // 矩形区域
    
    mPaint.setColor(Color.BLACK);           // 绘制黑色矩形
    canvas.drawRect(rect,mPaint);
    
    canvas.scale(0.5f,0.5f);                // 画布缩放
    
    mPaint.setColor(Color.BLUE);            // 绘制蓝色矩形
    canvas.drawRect(rect,mPaint);
    

    示例二:

    // 将坐标系原点移动到画布正中心
    canvas.translate(mWidth / 2, mHeight / 2);
    
    RectF rect = new RectF(0,-400,400,0);   // 矩形区域
    
    mPaint.setColor(Color.BLACK);           // 绘制黑色矩形
    canvas.drawRect(rect,mPaint);
    
    canvas.scale(0.5f,0.5f,200,0);          // 画布缩放  <-- 缩放中心向右偏移了200个单位
    
    mPaint.setColor(Color.BLUE);            // 绘制蓝色矩形
    canvas.drawRect(rect,mPaint);
    

    示例三:

    // 将坐标系原点移动到画布正中心
    canvas.translate(mWidth / 2, mHeight / 2);
    
    RectF rect = new RectF(0,-400,400,0);   // 矩形区域
    
    mPaint.setColor(Color.BLACK);           // 绘制黑色矩形
    canvas.drawRect(rect,mPaint);
    
    canvas.scale(-0.5f,-0.5f,200,0);          // 画布缩放  <-- 缩放中心向右偏移了200个单位
    
    mPaint.setColor(Color.BLUE);            // 绘制蓝色矩形
    canvas.drawRect(rect,mPaint);
    

    注意A、B、C、D点。


    缩放范围

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

    注意事项

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

    rotate()——旋转

    旋转方法

    public void rotate (float degrees);
    // 后面两个参数控制旋转中心点,默认的旋转中心是坐标原点
    public final void rotate (float degrees, float px, float py);
    

    示例一

    // 将坐标系原点移动到画布正中心
    canvas.translate(mWidth / 2, mHeight / 2);
    
    RectF rect = new RectF(0,-400,400,0);   // 矩形区域
    
    mPaint.setColor(Color.BLACK);           // 绘制黑色矩形
    canvas.drawRect(rect,mPaint);
    
    canvas.rotate(180);                     // 旋转180度 <-- 默认旋转中心为原点
    
    mPaint.setColor(Color.BLUE);            // 绘制蓝色矩形
    canvas.drawRect(rect,mPaint);
    

    示例二

    改变旋转中心。

    // 将坐标系原点移动到画布正中心
    canvas.translate(mWidth / 2, mHeight / 2);
    
    RectF rect = new RectF(0,-400,400,0);   // 矩形区域
    
    mPaint.setColor(Color.BLACK);           // 绘制黑色矩形
    canvas.drawRect(rect,mPaint);
    
    canvas.rotate(180,200,0);               // 旋转180度 <-- 旋转中心向右偏移200个单位
    
    mPaint.setColor(Color.BLUE);            // 绘制蓝色矩形
    canvas.drawRect(rect,mPaint);
    

    示例三

    // 将坐标系原点移动到画布正中心
    canvas.translate(mWidth / 2, mHeight / 2);
    
    canvas.drawCircle(0,0,400,mPaint);          // 绘制两个圆形
    canvas.drawCircle(0,0,380,mPaint);
    
    for (int i=0; i<=360; i+=10){               // 绘制圆形之间的连接线
       canvas.drawLine(0,380,0,400,mPaint);
       canvas.rotate(10);
    }
    

    注意事项

    • 旋转是叠加的。

    skew()——错切

    错切方法

    // 将画布在x方向上倾斜相应的角度,sx倾斜角度的tan值,
    // 将画布在y轴方向上倾斜相应的角度,sy为倾斜角度的tan值.
    public void skew(float sx, float sy);
    

    计算方法

    math x = x + sx \times y
    math y = sy * x \times y

    示例一

    // 将坐标系原点移动到画布正中心
    canvas.translate(mWidth / 2, mHeight / 2);
    
    RectF rect = new RectF(0,0,200,200);   // 矩形区域
    
    mPaint.setColor(Color.BLACK);           // 绘制黑色矩形
    canvas.drawRect(rect,mPaint);
    
    canvas.skew(1,0);                       // 水平错切 <- 45度
    
    mPaint.setColor(Color.BLUE);            // 绘制蓝色矩形
    canvas.drawRect(rect,mPaint);
    

    示例二

    // 将坐标系原点移动到画布正中心
    canvas.translate(mWidth / 2, mHeight / 2);
    
    RectF rect = new RectF(0,0,200,200);   // 矩形区域
    
    mPaint.setColor(Color.BLACK);           // 绘制黑色矩形
    canvas.drawRect(rect,mPaint);
    
    canvas.skew(1,0);                       // 水平错切
    canvas.skew(0,1);                       // 垂直错切
    
    mPaint.setColor(Color.BLUE);            // 绘制蓝色矩形
    canvas.drawRect(rect,mPaint);
    

    注意事项

    • 错切是可叠加的,并且调用次序不同绘制结果也会不同

    save() / restore()——快照/回滚

    相关API

    相关API 简介
    save() 把当前的画布的状态进行保存,然后放入特定的栈中
    saveLayer*() 新建一个图层,并放入特定的栈中
    restore() 把栈中最顶层的画布状态取出来,并按照这个状态恢复当前的画布
    restoreToCount() 弹出指定位置及其以上所有的状态,并按照指定位置的状态进行恢复
    getSaveCount() 获取栈中内容的数量(即保存次数)
    名称 简介
    ALL_SAVE_FLAG 默认,保存全部状态
    CLIP_SAVE_FLAG 保存剪辑区
    CLIP_TO_LAYER_SAVE_FLAG 剪裁区作为图层保存
    FULL_COLOR_LAYER_SAVE_FLAG 保存图层的全部色彩通道
    HAS_ALPHA_LAYER_SAVE_FLAG 保存图层的alpha(不透明度)通道
    MATRIX_SAVE_FLAG 保存Matrix信息(translate, rotate, scale, skew)

    FAQ

    Q :什么是画布和图层?
    A :实际上我们看到的画布是由多个图层构成的。在通常情况下,使用默认图层就可满足需求,但是如果需要绘制比较复杂的内容,如地图(地图可以有多个地图层叠加而成,比如:政区层,道路层,兴趣点层)等,则分图层绘制比较好一些。

    save()

    // 保存全部状态
    public int save();
    // 根据saveFlags参数保存一部分状态
    public int save(int saveFlags);
    

    saveLayer*()

    // 无图层alpha(不透明度)通道
    public int saveLayer (RectF bounds, Paint paint)
    public int saveLayer (RectF bounds, Paint paint, int saveFlags)
    public int saveLayer (float left, float top, float right, float bottom, Paint paint)
    public int saveLayer (float left, float top, float right, float bottom, Paint paint, int saveFlags)
    
    // 有图层alpha(不透明度)通道
    public int saveLayerAlpha (RectF bounds, int alpha)
    public int saveLayerAlpha (RectF bounds, int alpha, int saveFlags)
    public int saveLayerAlpha (float left, float top, float right, float bottom, int alpha)
    public int saveLayerAlpha (float left, float top, float right, float bottom, int alpha, int saveFlags)
    

    注意性能。

    restore()

    状态回滚,就是从栈顶取出一个状态然后根据内容进行恢复。

    restoreToCount()

    弹出指定位置以及以上所有状态,并根据指定位置状态进行恢复。

    getSaveCount()

    获取保存的次数,即状态栈中保存状态的数量。

    相关文章

      网友评论

          本文标题:★60.自定义控件 ★05.Canvas之画布操作

          本文链接:https://www.haomeiwen.com/subject/txipcxtx.html