Android Canvas进阶常用API

一、canvas位置变换

自定义一个TransformView继承自view,在构造方法中初始化画笔(paint):

public class TransformView extends View {

    private Paint mPaint;

    public TransformView(Context context) {
        this(context, null);
    }

    public TransformView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public TransformView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        mPaint = new Paint();
        mPaint.setColor(Color.RED);
        mPaint.setStrokeWidth(4);
        mPaint.setStyle(Paint.Style.STROKE);
    }
    
    ...

}

画笔初始化完成后在ondraw方法中,我们今天的主角canvas登场。

1.平移操作

        canvas.translate(50, 50);//将画布坐标右移50,下移50
        canvas.drawRect(0,0, 400, 400, mPaint);//画一个红色矩形
        canvas.translate(50, 50);//将画布坐标再次右移50,下移50
        mPaint.setColor(Color.GRAY);//画笔颜色改为灰色
        canvas.drawRect(0,0, 400, 400, mPaint);//画一个相对画布不变的灰色矩形
        canvas.drawLine(0, 0, 600,600, mPaint);//画一条线,起点左边0,0,终点坐标600,600

从代码和效果图可以看出,canvas平移后,起点坐标也就跟着移动了,需要注意的是translate(float dx, float dy)函数的两个参数dx,dy是相对量,是相对平移前画布的坐标,比如连续执行两次canvas.translate(50, 50),其实画布是相对之前,像右和下各平移了100px。

2.缩放操作

        mPaint.setColor(Color.RED);//画笔颜色改为红色
        canvas.drawRect(200,200, 700,700, mPaint);//画一个红色矩形
        canvas.scale(0.5f, 0.5f);//画布缩放为原来的0.5倍
        mPaint.setColor(Color.GRAY);//画笔颜色改为灰色
        canvas.drawRect(200,200, 700,700, mPaint);//画一个相对画布不变的灰色矩形
        canvas.drawLine(200,200, 600, 600, mPaint);//画一条线,起点左边200,200,终点坐标600,600

canvas.scale(0.5f, 0.5f);是将画布的横坐标和纵坐标都压缩为原来的一半,但是压缩后的坐标原点和压缩前的坐标原点在同一个地方,都是画布的左上角,那么肯定有指定左边原点的方法,那就是4个参数的scale,scale(float sx, float sy, float px, float py),其中sx和sy还是缩放系数,px和py则是相对于缩放前画布的坐标,该点为缩放前后画布的重合点,看起源码也很容易理解

public final void scale(float sx, float sy, float px, float py) {
    if (sx == 1.0f && sy == 1.0f) return;
    translate(px, py);
    scale(sx, sy);
    translate(-px, -py);
}

其实scale(float sx, float sy, float px, float py)相当于3步操作,我们对上面的栗子进行改造

        mPaint.setColor(Color.RED);//画笔颜色改为红色
        canvas.drawRect(200,200, 700,700, mPaint);//画一个红色矩形
        canvas.scale(0.5f, 0.5f, 700,700);//画布缩放为原来的0.5倍,并且缩放前后坐标重叠点在缩放前的700,700处
        mPaint.setColor(Color.GRAY);//画笔颜色改为灰色
        canvas.drawRect(200,200, 700,700, mPaint);//画一个相对画布不变的灰色矩形
        canvas.drawLine(200,200, 600, 600, mPaint);//画一条线,起点左边200,200,终点坐标600,600

3.旋转操作

        canvas.translate(50,50);//先将画布右下平移50px,方便查看效果
        mPaint.setColor(Color.RED);//画笔颜色改为红色
        canvas.drawRect(0,0, 700,700, mPaint);//画一个红色矩形
        canvas.rotate(45);//旋转45°
        mPaint.setColor(Color.GRAY);//更改画笔为灰色
        canvas.drawRect(0,0, 700,700, mPaint);//画一个大小相同灰色矩形

可以看到rotate(float degrees)的角度degrees是顺时针旋转的,一个参数的旋转中心是在画布的0,0坐标处,当然也可以指定旋转中心,rotate(float degrees, float px, float py)即指定旋转中心为(x,y),改造上面的代码

        canvas.translate(50,50);//先将画布右下平移50px,方便查看效果
        mPaint.setColor(Color.RED);//画笔颜色改为红色
        canvas.drawRect(0,0, 700,700, mPaint);//画一个红色矩形
        canvas.rotate(45, 350, 350); //px, py表示旋转中心的坐标
        mPaint.setColor(Color.GRAY);//更改画笔为灰色
        canvas.drawRect(0,0, 700,700, mPaint);//画一个大小相同灰色矩形

4.倾斜操作

倾斜操作skew(float sx, float sy)有2个参数,第一个参数sx代表在X方向倾斜,Y轴逆时针旋转,第二个参数sy代表在y方向倾斜, X轴顺时针旋转,该函数用的较少,笔者也似懂非懂

        canvas.drawRect(0,0, 400, 400, mPaint);
        canvas.skew(1, 0); //在X方向倾斜45度,Y轴逆时针旋转45
        mPaint.setColor(Color.GRAY);
        canvas.drawRect(0, 0, 400, 400, mPaint);

5.切割

简单讲就是裁剪画布,画布裁剪后只在裁剪区域内绘制有效,同理还有反向切割,反向切割后只在反向切割范围内有效

        canvas.drawRect(200, 200,700, 700, mPaint);
        mPaint.setColor(Color.GRAY);
        canvas.drawRect(200, 800,700, 1300, mPaint);
        canvas.clipRect(200, 200,700, 700); //画布被裁剪
        canvas.drawCircle(100,100, 100,mPaint); //坐标超出裁剪区域,无法绘制
        canvas.drawCircle(300, 300, 100, mPaint); //坐标区域在裁剪范围内,绘制成功

 

        canvas.drawRect(200, 200,700, 700, mPaint);
        mPaint.setColor(Color.GRAY);
        canvas.drawRect(200, 800,700, 1300, mPaint);
        canvas.clipOutRect(200,200,700,700); //画布裁剪外的区域
        canvas.drawCircle(100,100,100,mPaint); //坐标区域在裁剪范围内,绘制成功
        canvas.drawCircle(300, 300, 100, mPaint);//坐标超出裁剪区域,无法绘制

6.矩阵

我们可以通过矩阵实现平移、缩放、旋转等操作

 //矩阵
        canvas.drawRect(0,0,700,700, mPaint);
        Matrix matrix = new Matrix();
        matrix.setTranslate(50,50);
//        matrix.setRotate(45);
//        matrix.setScale(0.5f, 0.5f);
        canvas.setMatrix(matrix);
        mPaint.setColor(Color.GRAY);
        canvas.drawRect(0,0,700,700, mPaint);

二、canvas状态保存恢复

1.canvas内部对于状态的保存存放在栈中;

2.可以多次调用save保存canvas的状态,并且可以通过getSaveCount方法获取保存的状态个数;

3.可以通过restore方法返回最近一次save前的状态,也可以通过restoreToCount返回指定save状态。指定save状态之后的状态全部被清除;

4.saveLayer可以创建新的图层,之后的绘制都会在这个图层之上绘制,直到调用restore方法。

注意:绘制的坐标系不能超过图层的范围, saveLayerAlpha对图层增加了透明度信息。

        Log.e(TAG, "onDraw: " + canvas.getSaveCount());//打印1
        canvas.drawRect(200, 200, 700, 700, mPaint);
        int state = canvas.save();//save一次,state=1,getSaveCount+1 = 2
        Log.e(TAG, "onDraw: " + canvas.getSaveCount());//打印2
        canvas.translate(50, 50);
        mPaint.setColor(Color.GRAY);
        canvas.drawRect(0, 0, 500, 500, mPaint);
        canvas.save();//save一次,getSaveCount+1 = 3
        Log.e(TAG, "onDraw: " + canvas.getSaveCount());//打印3
        canvas.translate(50, 50);
        mPaint.setColor(Color.BLUE);
        canvas.drawRect(0, 0, 500, 500, mPaint);
        canvas.restore();//restore一次,getSaveCount -1 =2
        Log.e(TAG, "onDraw: " + canvas.getSaveCount());//打印2
        canvas.restore();//restore一次,getSaveCount -1 = 1
        Log.e(TAG, "onDraw: " + canvas.getSaveCount());//打印1
        canvas.restoreToCount(state);//恢复到statue = 1之前,即getSaveCount = 1
        Log.e(TAG, "onDraw: " + canvas.getSaveCount());//打印1

2019-09-05 22:25:19.356 18398-18398/com.itzb.paintdemo E/SaveRestoreView: onDraw: 1
2019-09-05 22:25:19.356 18398-18398/com.itzb.paintdemo E/SaveRestoreView: onDraw: 2
2019-09-05 22:25:19.356 18398-18398/com.itzb.paintdemo E/SaveRestoreView: onDraw: 3
2019-09-05 22:25:19.357 18398-18398/com.itzb.paintdemo E/SaveRestoreView: onDraw: 2
2019-09-05 22:25:19.357 18398-18398/com.itzb.paintdemo E/SaveRestoreView: onDraw: 1
2019-09-05 22:25:19.358 18398-18398/com.itzb.paintdemo E/SaveRestoreView: onDraw: 1

 

另外离屏绘制在图层混合模式(Xfermode)已经使用过,这里在摘出来

        canvas.drawRect(200,200, 700,700, mPaint);
        int layerId = canvas.saveLayer(0,0, 700, 700, mPaint);//离屏绘制开始
        mPaint.setColor(Color.GRAY);
        Matrix matrix = new Matrix();
        matrix.setTranslate(100,100);
        canvas.setMatrix(matrix);
        canvas.drawRect(0,0,700,700, mPaint); //由于平移操作,导致绘制的矩形超出了图层的大小,所以绘制不完全
        canvas.restoreToCount(layerId);//离屏绘制结束
        
        mPaint.setColor(Color.RED);
        canvas.drawRect(0,0,100,100, mPaint);

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值