自定義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(0,0,100,100,mPaint);
        //畫出座標系
        drawAxis(canvas,Color.RED);


    }
private void drawAxis(Canvas canvas, @ColorInt int color){
        mPaint.setStrokeWidth(10);
        mPaint.setColor(color);
        canvas.drawLine(0,0,400,0,mPaint);
        canvas.drawLine(0,0,0,400,mPaint);
    }

這裏寫圖片描述

現在我們執行translate方法

        canvas.translate(500,500);
        mPaint.setColor(Color.GREEN);
        canvas.drawRect(0,0,100,100,mPaint);
        drawAxis(canvas,Color.RED);

這裏寫圖片描述
這個沒問題,translate執行後,座標系的確移動了,現在我們來看rotate(degress)

        canvas.rotate(45);
        mPaint.setColor(Color.BLACK);
        canvas.drawRect(0,0,100,100,mPaint);
        drawAxis(canvas,Color.BLUE);

這裏寫圖片描述
座標系也的確旋轉了,那我們接着來看下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(500,500);
        mPaint.setColor(Color.GREEN);
        canvas.drawRect(0,0,100,100,mPaint);
        //畫出座標系
        drawAxis(canvas,Color.RED);
        //移動
        canvas.translate(500,500);
        mPaint.setColor(Color.GREEN);
        canvas.drawRect(0,0,100,100,mPaint);
        drawAxis(canvas,Color.RED);
        //旋轉
        canvas.rotate(45);
        mPaint.setColor(Color.BLACK);
        canvas.drawRect(0,0,100,100,mPaint);
        drawAxis(canvas,Color.BLUE);
        //到這已經改變了角度和座標,我們先復原
        canvas.rotate(-45);
        canvas.translate(-500,-500);
        //再來重新rotate(45,500,500);
        mPaint.setColor(Color.GRAY);
        canvas.rotate(45,500,500);
        canvas.drawRect(0,0,100,100,mPaint);
        drawAxis(canvas,Color.BLACK);
    }

爲了更好地看到效果,我們將初始座標移動至(500,500),效果如下:
這裏寫圖片描述
什麼情況,怎麼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);

        //爲看到更好的效果,我們統一將座標移動到(500,500)
        canvas.translate(500,500);
        mPaint.setColor(Color.GREEN);
        canvas.drawRect(0,0,100,100,mPaint);
        //畫出座標系
        drawAxis(canvas,Color.RED);
        canvas.save();
        //移動
        canvas.translate(500,500);
        mPaint.setColor(Color.GREEN);
        canvas.drawRect(0,0,100,100,mPaint);
        drawAxis(canvas,Color.RED);
        //旋轉
        canvas.rotate(45);
        mPaint.setColor(Color.BLACK);
        canvas.drawRect(0,0,100,100,mPaint);
        drawAxis(canvas,Color.BLUE);
        canvas.restore();
        //再次畫圖
        mPaint.setColor(Color.GRAY);
        canvas.drawRect(0,0,60,60,mPaint);
        drawAxis(canvas,Color.BLACK);
    }

這裏寫圖片描述
看到沒,在save和restore之間做的圖,直接顯示在屏幕上了,但是在save之前和restore之後的座標系真沒有改變,是不是恨好奇?
其實,用個ps的人都知道,save和restore之間其實是在新的層上面了,save和restore之外的部分纔是同層上做操作,兩層的操作肯定不干擾了,ok,這下明白了吧!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章