Canvas詳解

概念

畫布,通過畫筆繪製幾何圖形,文本,路徑和位圖等

常用API類型

常用API分爲3類 :繪製,變換,狀態保存和恢復

第二類: 變換

基本類

ca

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);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        ....
        這裏寫操作
    }

}

都在onDraw中寫

平移操作

        canvas.drawRect(0,0, 400, 400, mPaint);
        canvas.translate(50, 50);
        mPaint.setColor(Color.GRAY);
        canvas.drawRect(0,0, 400, 400, mPaint);
        canvas.drawLine(0, 0, 600,600, mPaint);

縮放操作

        canvas.drawRect(200,200, 700,700, mPaint);
        canvas.scale(0.5f, 0.5f);
        mPaint.setColor(Color.GRAY);
        canvas.drawRect(200,200, 700,700, mPaint);
顯示

在這裏插入圖片描述

修改

修改如下代碼效果如圖:

        canvas.drawRect(200,200, 700,700, mPaint);
//        canvas.scale(0.5f, 0.5f);
        
        //先translate(px, py),再scale(sx, sy),再反響translate
        canvas.scale(0.5f, 0.5f, 200,200);
        mPaint.setColor(Color.GRAY);
        canvas.drawRect(200,200, 700,700, mPaint);
顯示

在這裏插入圖片描述

 //先translate(px, py),再scale(sx, sy),再反響translate
    canvas.scale(0.5f, 0.5f, 200,200);

等同於

        canvas.translate(200, 200);
        canvas.scale(0.5f, 0.5f);
        canvas.translate(-200, -200);

旋轉操作

        canvas.translate(50,50);
        canvas.drawRect(0,0, 700,700, mPaint);
        canvas.rotate(45);
        mPaint.setColor(Color.GRAY);
        canvas.drawRect(0,0, 700,700, mPaint);

在這裏插入圖片描述

旋轉中心
        canvas.drawRect(400, 400, 900, 900, mPaint);
        canvas.rotate(45, 650, 650); //px, py表示旋轉中心的座標
        mPaint.setColor(Color.GRAY);
        canvas.drawRect(400, 400, 900, 900, mPaint);

在這裏插入圖片描述

傾斜操作

 /**
 * @params sx  將畫布在x方向上傾斜相應的角度,sx傾斜角度的tan值,其實就是將y逆時針旋轉相應的角度
 * @params sy 將畫布在y方向上傾斜相應的角度,sx傾斜角度的tan值,其實就是將x順時針旋轉相應的角度
 *
public void skew (float sx, float sy)
        canvas.drawRect(0,0, 400, 400, mPaint);
        canvas.skew((float) Math.sqrt(3), 0); 
        mPaint.setColor(Color.GRAY);
        canvas.drawRect(0, 0, 400, 400, mPaint);

首先
明確X軸Y軸方向:

在這裏插入圖片描述代碼中

 canvas.skew((float) Math.sqrt(3), 0); 

其次
明確參數:

     @params sx  sx傾斜角度的tan值
     @params sy sy傾斜角度的tan值

tan值 三角函數 tanθ =x/y, 這裏的xy 不是sx,sy

常用的有:

tanθ 爲45° 爲1
tanθ 爲60° 爲根號3
tanθ 爲30° 爲3分之根號3

代碼中:

canvas.skew((float) Math.sqrt(3), 0); 

sx:
爲(float) Math.sqrt(3) 即 根號3 60°。

意思是y軸逆時針旋轉60度

sy:不變即x軸不變
如圖:
紅色的爲原先的矩形,灰色爲之後的圖形
在這裏插入圖片描述

再比如:

 canvas.drawRect(0,0, 400, 400, mPaint);
        canvas.skew((float) Math.sqrt(3)/3, 0); 
        mPaint.setColor(Color.GRAY);
        canvas.drawRect(0, 0, 400, 400, mPaint);

代碼中:

 canvas.skew((float) Math.sqrt(3)/3, 0); 

sx:
爲(float) Math.sqrt(3) 即 3分之根號3 30°。

意思是y軸逆時針旋轉30度

sy:不變即x軸不變
在這裏插入圖片描述
同理,反過來

        canvas.drawRect(0,0, 400, 400, mPaint);
        canvas.skew(0, (float) Math.sqrt(3)/3); 
        mPaint.setColor(Color.GRAY);
        canvas.drawRect(0, 0, 400, 400, mPaint);

代碼中:

     canvas.skew(0, (float) Math.sqrt(3)/3); 

sx:不變即y軸不變
sy:
爲(float) Math.sqrt(3) 即 3分之根號3 30°。

意思是x軸順時針旋轉30度

在這裏插入圖片描述

總結:
 sx 將畫布在x方向上傾斜相應的角度,sx傾斜角度的tan值,其實就是將y逆時針旋轉相應的角度
 sy 將畫布在y方向上傾斜相應的角度,sx傾斜角度的tan值,其實就是將x順時針旋轉相應的角度

切割

裁剪clipRect
        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); //座標區域在裁剪範圍內,繪製成功
反向裁剪 :clipOutRect
        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);//座標超出裁剪區域,無法繪製

矩陣

        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調用了translate,scale,rotate,skew,clipRect等變換後,後續的操作都是基於變換後的Canvas,都會受到影響,對於後續的操作很不方便。Canvas提供了save,saveLayer,saveLayerAlpha,restore,restoreToCount來保存和恢復狀態。

        mPaint.setColor(Color.GRAY);
        canvas.drawRect(0,0,500,500,mPaint);
        
        canvas.translate(50,50);
        
        mPaint.setColor(Color.GRAY);
        
        canvas.drawRect(0,0,500,500,mPaint);

畫了兩個矩形
在這裏插入圖片描述
如果我們想在原點再畫一條線。需要如下代碼

        mPaint.setColor(Color.GRAY);
        canvas.drawRect(0,0,500,500,mPaint);

        canvas.translate(50,50);

        mPaint.setColor(Color.GRAY);

        canvas.drawRect(0,0,500,500,mPaint);

        canvas.translate(-50,-50);
        canvas.drawLine(0,0,400,500,mPaint);

在這裏插入圖片描述

我們可以用canvas中的save方法來進行保存,不用

canvas.translate(-50,-50);

平移回來

        mPaint.setColor(Color.GRAY);
        canvas.drawRect(0,0,500,500,mPaint);
        //保存狀態
        canvas.save();
        canvas.translate(50,50);

        mPaint.setColor(Color.GRAY);

        canvas.drawRect(0,0,500,500,mPaint);
        //恢復狀態
        canvas.restore();
//        canvas.translate(-50,-50);
        canvas.drawLine(0,0,400,500,mPaint);

也可以達到上圖效果。

如果save()保存了兩次,restore()了一次,只是回到最近一次的save()方法。

如下代碼並沒有在原點繪製,而是在第二次保存的位置繪製。
即 canvas.translate(50,50); 位置繪製。

 mPaint.setColor(Color.GRAY);
        canvas.drawRect(0,0,500,500,mPaint);
        canvas.save();
        canvas.translate(50,50);

        mPaint.setColor(Color.RED);
        canvas.drawRect(0,0,500,500,mPaint);

        canvas.save();
        canvas.translate(50,50);
        mPaint.setColor(Color.BLUE);

        canvas.drawRect(0,0,500,500,mPaint);
        canvas.restore();

        canvas.drawLine(0,0,400,500,mPaint);

如圖
在這裏插入圖片描述調用兩次restore方法:

 mPaint.setColor(Color.GRAY);
        canvas.drawRect(0,0,500,500,mPaint);
        canvas.save();
        canvas.translate(50,50);

        mPaint.setColor(Color.RED);
        canvas.drawRect(0,0,500,500,mPaint);

        canvas.save();
        canvas.translate(50,50);
        mPaint.setColor(Color.BLUE);

        canvas.drawRect(0,0,500,500,mPaint);
        canvas.restore();
        canvas.restore();
//        canvas.translate(-50,-50);
        canvas.drawLine(0,0,400,500,mPaint);

如圖
在這裏插入圖片描述
canvas.getSaveCount():可以用來查看save的次數。
默認爲1.

通過

  int state = canvas.save();
   canvas.restoreToCount(state);

可以回到 state 時的狀態

還可以通過layerId和 canvas.restoreToCount(layerId); 來達到重置效果。

        /**
         * 1.canvas內部對於狀態的保存存放在棧中
         * 2.可以多次調用save保存canvas的狀態,並且可以通過getSaveCount方法獲取保存的狀態個數
         * 3.可以通過restore方法返回最近一次save前的狀態,也可以通過restoreToCount返回指定save狀態。指定save狀態之後的狀態全部被清除
         * 4.saveLayer可以創建新的圖層,之後的繪製都會在這個圖層之上繪製,直到調用restore方法
         * 注意:繪製的座標系不能超過圖層的範圍, saveLayerAlpha對圖層增加了透明度信息
         */
        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);

總結:

  • canvas內部對於狀態的保存存放在棧中
  • 可以多次調用save保存canvas的狀態,並且可以通過getSaveCount方法獲取保存的狀態個數
  • 可以通過restore方法返回最近一次save前的狀態,也可以通過restoreToCount返回指定save狀態。指定save狀態之後的狀態全部被清除
  • saveLayer可以創建新的圖層,之後的繪製都會在這個圖層之上繪製,直到調用restore方法,
    注意:繪製的座標系不能超過圖層的範圍, saveLayerAlpha對圖層增加了透明度信息
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章