Android自定义View学习四---Canvas画布操作

Posted winfredzen

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android自定义View学习四---Canvas画布操作相关的知识,希望对你有一定的参考价值。

Canvas之画布操作

内容来自:安卓自定义View进阶-Canvas之画布操作

基本操作

位移

translate是坐标系的移动,位移是基于当前位置移动,而不是每次基于屏幕左上角的(0,0)点移动

        // 绘制矩形
        mPaint.setColor(Color.RED);
        mPaint.setStyle(Paint.Style.STROKE);
        canvas.drawRect(new Rect(0, 0, 200, 200), mPaint);

        // 在坐标原点绘制一个黑色圆形
        mPaint.setColor(Color.BLACK);
        mPaint.setStyle(Paint.Style.FILL);
        canvas.translate(200, 200);
        canvas.drawCircle(100, 100, 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)

缩放的中心默认为坐标原点,而缩放中心轴就是坐标轴,第二个方法的pxpy,用来控制缩放中心位置

// 将坐标系原点移动到画布正中心
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);          // 画布缩放

mPaint.setColor(Color.BLUE);            // 绘制蓝色矩形
canvas.drawRect(rect,mPaint);

和位移(translate)一样,缩放也是可以叠加的,如下的例子:

        // 将坐标系原点移动到画布正中心
        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);
        

旋转

旋转提供了两种方法:

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

skew只提供了一种方法

public void skew (float sx, float sy)
  • sx - 将画布在x方向上倾斜相应的角度,sx倾斜角度的tan
  • sy - 将画布在y轴方向上倾斜相应的角度,sy为倾斜角度的tan
// 将坐标系原点移动到画布正中心
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);

save和restore

我的理解,类似于iosCGContextSaveGStateCGContextRestoreGState

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

状态栈

状态栈可以存储画布状态和图层状态

save

save 有两种方法:

// 保存全部状态
public int save ()

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

可以看到第二种方法比第一种多了一个saveFlags参数,使用这个参数可以只保存一部分状态,更加灵活。saveFlags参数,参见下表

名称简介
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)

常用格式

save();      //保存状态
...          //具体操作
restore();   //回滚到之前的状态

以上是关于Android自定义View学习四---Canvas画布操作的主要内容,如果未能解决你的问题,请参考以下文章

Android自定义View学习一---基础

Android自定义View学习二---流程

Android自定义ViewGroup(四打造自己的布局容器)

Android之自定义View学习

Android自定义View初步

Android View体系自定义View