天天看點

自定義view(1)canvas使用

欲先攻其事必先利其器,想要做好自定義view,就必須先将canvas掌握,面對canvas,我們在心中必先要有個這樣的意識,canvas是無限大的,而之是以我們看到了隻有螢幕大小,那是螢幕給我們帶來的迷惑,廢話不多說,今天我們主要來聊canvas中常用用法,translate,rotate,save,restore等功能,估計大夥都覺得這幾個功能很簡單嘛,網上随便一搜一大把,其實到了一些真正細節的東西都含糊其詞了。

是不是大家之前一直存在一下觀點:

translate移動改變了canvas的坐标,rotate(degress)改變了canvas的坐标角度,而rotate(degress,x,y)效果相當于translate(x,y)+rotate(degress)但沒有改變canvas坐标?真相是否如此,咱們看代碼和圖

先圖個矩形且畫出坐标:

protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        mPaint.setColor(Color.GREEN);
        canvas.drawRect(,,,,mPaint);
        //畫出坐标系
        drawAxis(canvas,Color.RED);


    }
private void drawAxis(Canvas canvas, @ColorInt int color){
        mPaint.setStrokeWidth();
        mPaint.setColor(color);
        canvas.drawLine(,,,,mPaint);
        canvas.drawLine(,,,,mPaint);
    }
           
自定義view(1)canvas使用

現在我們執行translate方法

canvas.translate(,);
        mPaint.setColor(Color.GREEN);
        canvas.drawRect(,,,,mPaint);
        drawAxis(canvas,Color.RED);
           
自定義view(1)canvas使用

這個沒問題,translate執行後,坐标系的确移動了,現在我們來看rotate(degress)

canvas.rotate();
        mPaint.setColor(Color.BLACK);
        canvas.drawRect(,,,,mPaint);
        drawAxis(canvas,Color.BLUE);
           
自定義view(1)canvas使用

坐标系也的确旋轉了,那我們接着來看下rotate(45,x,y)和translate(x,y)+rotate(45)效果是不是一樣?前者是否改變了原來的坐标系呢?

其實translate(x,y)+rotate(45)的效果前面我們已經看到了,他的确既改變坐标又改變了角度,接下來我們看看rotate(45,x,y)是不是和前者重合?

protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        //為看到更好的效果,我們統一将坐标移動到(500,500)
        canvas.translate(,);
        mPaint.setColor(Color.GREEN);
        canvas.drawRect(,,,,mPaint);
        //畫出坐标系
        drawAxis(canvas,Color.RED);
        //移動
        canvas.translate(,);
        mPaint.setColor(Color.GREEN);
        canvas.drawRect(,,,,mPaint);
        drawAxis(canvas,Color.RED);
        //旋轉
        canvas.rotate();
        mPaint.setColor(Color.BLACK);
        canvas.drawRect(,,,,mPaint);
        drawAxis(canvas,Color.BLUE);
        //到這已經改變了角度和坐标,我們先複原
        canvas.rotate(-);
        canvas.translate(-,-);
        //再來重新rotate(45,500,500);
        mPaint.setColor(Color.GRAY);
        canvas.rotate(,,);
        canvas.drawRect(,,,,mPaint);
        drawAxis(canvas,Color.BLACK);
    }
           

為了更好地看到效果,我們将初始坐标移動至(500,500),效果如下:

自定義view(1)canvas使用

什麼情況,怎麼rotate(45)+translate(500,500)和rotate(45,500,500)效果完全不同呢,而且後者畫的東西完全不符合邏輯嘛,是不是颠覆我們的想法?究竟rotate(45,500,500)做了什麼?直接上源碼:

public final void  rotate(float degrees, float px, float py) {
     translate(px, py);
     rotate(degrees);
     translate(-px, -py);
    }
           

看到沒,源碼是在移動坐标旋轉角度後,再回複坐标,此時還能恢複不?答案是肯定不能的,除非先恢複坐标系的角度,然後再恢複,那才能恢複到原來的坐标點,現在知道原因了吧。

接着我們來看下,save和restore,這玩意究竟什麼用呢?聽說夾在這兩個玩意中間的任何操作都沒有改變原始坐标系,究竟是不是這樣?直接上demo

protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        //為看到更好的效果,我們統一将坐标移動到(,)
        canvas.translate(,);
        mPaint.setColor(Color.GREEN);
        canvas.drawRect(,,,,mPaint);
        //畫出坐标系
        drawAxis(canvas,Color.RED);
        canvas.save();
        //移動
        canvas.translate(,);
        mPaint.setColor(Color.GREEN);
        canvas.drawRect(,,,,mPaint);
        drawAxis(canvas,Color.RED);
        //旋轉
        canvas.rotate();
        mPaint.setColor(Color.BLACK);
        canvas.drawRect(,,,,mPaint);
        drawAxis(canvas,Color.BLUE);
        canvas.restore();
        //再次畫圖
        mPaint.setColor(Color.GRAY);
        canvas.drawRect(,,,,mPaint);
        drawAxis(canvas,Color.BLACK);
    }
           
自定義view(1)canvas使用

看到沒,在save和restore之間做的圖,直接顯示在螢幕上了,但是在save之前和restore之後的坐标系真沒有改變,是不是恨好奇?

其實,用個ps的人都知道,save和restore之間其實是在新的層上面了,save和restore之外的部分才是同層上做操作,兩層的操作肯定不幹擾了,ok,這下明白了吧!