自定義View之Canvas

在這裏插入圖片描述

1. 簡介

  • 定義:畫布,是一種繪製時的規則
  • 作用:規定繪製內容時的規則、內容
  1. 繪製內容是根據畫布的規定繪製在屏幕上的
  2. 理解爲: 畫布只是繪製時的規則,但內容實際上是繪製在屏幕上

2. Canvas的本質

  • 繪製內容時根據**畫布(Canvas)**的規定繪製在屏幕上
  • 畫布(Canvas)只會繪製時的規則,但實際上是繪製在屏幕上的

爲了更好更好說明繪製內容的本質和Canvas,請看下面例子

2.1 實例

  • 實例: 1. 先畫一個矩形(藍色);2. 然後移動畫布;3. 再畫一個矩形(紅色)
  • 代碼
 // 畫一個矩形(藍色)
        canvas.drawRect(100, 100, 150, 150, mPaint1);

        // 將畫布的原點移動到(400,500)
        canvas.translate(400,500);

        // 再畫一個矩形(紅色)
        canvas.drawRect(100, 100, 150, 150, mPaint2);
  • 效果圖
    在這裏插入圖片描述
  • 具體流程
    在這裏插入圖片描述
  • 總結
    繪製內容是根據畫布的規定繪製在屏幕上的。
  1. 內容實際上是繪製在屏幕上;
  2. 畫布,即Canvas,只是規定了繪製內容的規則;
  3. 內容的位置有座標決定,而座標是相對畫布而言的。

3.基礎

3.1 Paint類

  • 定義:畫筆
  • 作用:確定繪製內容的具體效果(如顏色、大小等等)
  • 具體使用:
  1. 創建一個畫筆對象
  2. 畫筆設置,即設置繪製內容的具體效果
  3. 初始化畫筆(儘量選在在View的構造函數)
    具體使用如下:
// 步驟1:創建一個畫筆
private Paint mPaint = new Paint();

// 步驟2:初始化畫筆
// 根據需求設置畫筆的各種屬性,具體如下:

    private void initPaint() {

        // 設置最基本的屬性
        // 設置畫筆顏色
        // 可直接引入Color類,如Color.red等
        mPaint.setColor(int color); 
        // 設置畫筆模式
         mPaint.setStyle(Style style); 
        // Style有3種類型:
        // 類型1:Paint.Style.FILLANDSTROKE(描邊+填充)
        // 類型2:Paint.Style.FILL(只填充不描邊)
        // 類型3:Paint.Style.STROKE(只描邊不填充)
        // 具體差別請看下圖:
        // 特別注意:前兩種就相差一條邊
        // 若邊細是看不出分別的;邊粗就相當於加粗       
        
        //設置畫筆的粗細
        mPaint.setStrokeWidth(float width)       
        // 如設置畫筆寬度爲10px
        mPaint.setStrokeWidth(10f);    

        // 不常設置的屬性
        // 得到畫筆的顏色     
        mPaint.getColor()      
        // 設置Shader
        // 即着色器,定義了圖形的着色、外觀
        // 可以繪製出多彩的圖形
        // 具體請參考文章:http://blog.csdn.net/iispring/article/details/50500106
        Paint.setShader(Shader shader)  

        //設置畫筆的a,r,p,g值
       mPaint.setARGB(int a, int r, int g, int b)      
         //設置透明度
        mPaint.setAlpha(int a)   
       //得到畫筆的Alpha值
        mPaint.getAlpha()        


        // 對字體進行設置(大小、顏色)
        //設置字體大小
          mPaint.setTextSize(float textSize)       

        // 文字Style三種模式:
          mPaint.setStyle(Style style); 
        // 類型1:Paint.Style.FILLANDSTROKE(描邊+填充)
        // 類型2:Paint.Style.FILL(只填充不描邊)
        // 類型3:Paint.Style.STROKE(只描邊不填充) 
        
      // 設置對齊方式   
      setTextAlign()
      // LEFT:左對齊
      // CENTER:居中對齊
      // RIGHT:右對齊

        //設置文本的下劃線
          setUnderlineText(boolean underlineText)      
        
        //設置文本的刪除線
        setStrikeThruText(boolean strikeThruText)    

         //設置文本粗體
        setFakeBoldText(boolean fakeBoldText)  
        
           // 設置斜體
        Paint.setTextSkewX(-0.5f);


        // 設置文字陰影
        Paint.setShadowLayer(5,5,5,Color.YELLOW);
     }

// 步驟3:在構造函數中初始化
    public CarsonView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initPaint();
    }

Style模式效果如下:
在這裏插入圖片描述

3.2 關閉硬件加速

  • 在Android 4.0的設備上,在打開硬件加速的情況下,使用自定義View可能出現問題。
  • 在測試前,先關閉硬件加速,具體如下:
// 在AndroidMenifest.xml的application節點添加
android:hardwareAccelerated="false"

4. Canvas的使用

4.1 對象創建和獲取

Canvas對象獲取方法有4種:

// 方法1
// 利用空構造方法直接創建對象
Canvas canvas = new Canvas()// 方法2
// 通過傳入裝載畫布Bitmap對象創建Canvas對象
// CBitmap上存儲所有繪製在Canvas的信息
Canvas canvas = new Canvas(bitmap)

// 方法3
// 通過重寫View.onDraw()創建Canvas對象
// 在該方法裏可以獲得這個View對應的Canvas對象

   @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //在這裏獲取Canvas對象
    }

// 方法4
// 在SurfaceView裏畫圖時創建Canvas對象

        SurfaceView surfaceView = new SurfaceView(this);
        // 從SurfaceView的surfaceHolder裏鎖定獲取Canvas
        SurfaceHolder surfaceHolder = surfaceView.getHolder();
        //獲取Canvas
        Canvas c = surfaceHolder.lockCanvas();
        
        // ...(進行Canvas操作)
        // Canvas操作結束之後解鎖並執行Canvas
        surfaceHolder.unlockCanvasAndPost(c);

官方推薦方法4來創建並獲取Canvas,因爲SurfaceView裏有一條線程是專門用於畫圖,所以方法4的畫圖性能最好,並使用於高刷新頻率的圖形。而方法3刷新頻率低於方法4,但系統花銷小,節省資源。

4.2 繪製方法是用

  • 利用Canvas類可畫出很多內容,如圖形、文字、線條等;
  • 對應方法如下:
    在這裏插入圖片描述
    下面逐個方法進行詳細講解:
    Canva具體使用時是複寫的onDraw()裏
4.2.1繪製顏色
  • 作用:將顏色填充整個畫布,常用於繪製底色
  • 具體使用
    // 傳入一個Color類的常量參數來設置畫布顏色
    // 繪製藍色
   canvas.drawColor(Color.BLUE); 
4.2.2 繪製基本圖形
  1. 繪製點
// 特別注意:需要用到畫筆Paint
// 所以之前記得創建畫筆
// 爲了區分,這裏使用了兩個不同顏色的畫筆

// 描繪一個點
// 在座標(200,200)處
canvas.drawPoint(300, 300, mPaint1);    

// 繪製一組點,座標位置由float數組指定
// 此處畫了3個點,位置分別是:(600,500)、(600,600)、(600,700)
canvas.drawPoints(new float[]{         
                600,500,
                600,600,
                600,700
        },mPaint2);
  1. 繪製直線(drawLine)
// 畫一條直線
// 在座標(100,200),(700,200)之間繪製一條直線
  canvas.drawLine(100,200,700,200,mPaint1);

// 繪製一組線
// 在座標(400,500),(500,500)之間繪製直線1
// 在座標(400,600),(500,600)之間繪製直線2
       canvas.drawLines(new float[]{
               400,500,500,500,
               400,600,500,600
       },mPaint2);
   }
  1. 繪製矩形(drawRect)
  • 原理:矩形的對角線頂點確定一個矩形(一般採用左上角和右下角的兩個點的座標)
  • 具體使用:
// 關於繪製矩形,Canvas提供了三種重載方法

       // 方法1:直接傳入兩個頂點的座標
       // 兩個頂點座標分別是:(100,100),(800,400)
        canvas.drawRect(100,100,800,400,mPaint);

        // 方法2:將兩個頂點座標封裝爲RectRectF
        Rect rect = new Rect(100,100,800,400);
        canvas.drawRect(rect,mPaint);

        // 方法3:將兩個頂點座標封裝爲RectF
        RectF rectF = new RectF(100,100,800,400);
        canvas.drawRect(rectF,mPaint);

        // 特別注意:Rect類和RectF類的區別
        // 精度不同:Rect = int & RectF = float

        // 三種方法畫出來的效果是一樣的。
  1. 繪製圓角矩形
  • 原理:矩形的對角線頂點確定一個矩形(類似於繪製矩形)
  • 具體使用:
       // 方法1:直接傳入兩個頂點的座標
       // API21時纔可使用
       // 第5、6個參數:rx、ry是圓角的參數,下面會詳細描述
       canvas.drawRoundRect(100,100,800,400,30,30,mPaint);
      
        // 方法2:使用RectF類
        RectF rectF = new RectF(100,100,800,400);
        canvas.drawRoundRect(rectF,30,30,mPaint);

在這裏插入圖片描述

  • 與矩形相比,圓角矩形多了兩個參數rx和ry
  • 圓角矩形的角是橢圓的圓弧
    在這裏插入圖片描述
  • 特別注意:當rx大於寬度一半,ry大於高度一半時,畫出來的爲橢圓

實際上,在rx爲寬度的一半,ry爲高度的一半時,剛好是一個橢圓;但由於當rx大於寬度一半,ry大於高度一半時,無法計算出圓弧,所以drawRoundRect對大於該數值的參數進行了修正,凡是大於一半的參數均按照一半來處理

  1. 繪製橢圓(drawOval)
  • 原理:矩形的對角線頂點確定矩形,根據傳入矩形的長寬作爲長軸和短軸畫橢圓
  • 具體使用
        // 方法1:使用RectF類
        RectF rectF = new RectF(100,100,800,400);
        canvas.drawOval(rectF,mPaint);

        // 方法2:直接傳入與矩形相關的參數
        canvas.drawOval(100,100,800,400,mPaint);

        // 爲了方便表示,畫一個和橢圓一樣參數的矩形
         canvas.drawRect(100,100,800,400,mPaint);

在這裏插入圖片描述
6. 繪製圓(drawCircle)

  • 原理:圓心座標+半徑決定圓
  • 具體使用:
// 參數說明:
// 1、2:圓心座標
// 3:半徑
// 4:畫筆

// 繪製一個圓心座標在(500,500),半徑爲400 的圓。
    canvas.drawCircle(500,500,400,mPaint);  
  1. 繪製圓弧
  • 原理:通過圓弧角度的起始位置和掃過地角度確定圓弧
  • 具體使用
// 繪製圓弧共有兩個方法
// 相比於繪製橢圓,繪製圓弧多了三個參數:
startAngle  // 確定角度的起始位置
sweepAngle // 確定掃過的角度
useCenter   // 是否使用中心(下面會詳細說明)

// 方法1
public void drawArc(@NonNull RectF oval, float startAngle, float sweepAngle, boolean useCenter, @NonNull Paint paint){}

// 方法2
public void drawArc(float left, float top, float right, float bottom, float startAngle,
            float sweepAngle, boolean useCenter, @NonNull Paint paint) {}

爲了理解第三個參數:userCenter,看一下示例:

// 以下示例:繪製兩個起始角度爲0度、掃過90度的圓弧
// 兩者的唯一區別就是是否使用了中心點

    // 繪製圓弧1(無使用中心)
        RectF rectF = new RectF(100, 100, 800,400);
        // 繪製背景矩形
        canvas.drawRect(rectF, mPaint1);
        // 繪製圓弧
        canvas.drawArc(rectF, 0, 90, false, mPaint2);

   // 繪製圓弧2(使用中心)
        RectF rectF2 = new RectF(100,600,800,900);
        // 繪製背景矩形
        canvas.drawRect(rectF2, mPaint1);
        // 繪製圓弧
        canvas.drawArc(rectF2,0,90,true,mPaint2);

在這裏插入圖片描述
可以得出:

  • 不使用中心點:圓弧的形狀=(起、止點連線+圓弧)構成的面積
  • 使用中心點:圓弧面積=(起點、圓心連線+止點、圓心連線+圓弧)構成的面積
4.2.3 繪製文字

繪製文字分爲三種應用場景

  • 情景1: 指定文本開始的位置
  1. 即指定文本基線位置
  2. 基線x默認在字符串左側,基線y默認在字符串下方
  • 情景2:指定每個文字的位置
  • 情景3:指定路徑,並根據路徑繪製文字

情況1:指定文本開始的位置

// 參數text:要繪製的文本
// 參數x,y:指定文本開始的位置(座標)

// 參數paint:設置的畫筆屬性
    public void drawText (String text, float x, float y, Paint paint)

// 實例
canvas.drawText("abcdefg",300,400,mPaint1);



// 僅繪製文本的一部分
// 參數start,end:指定繪製文本的位置
// 位置以下標標識,由0開始
    public void drawText (String text, int start, int end, float x, float y, Paint paint)
    public void drawText (CharSequence text, int start, int end, float x, float y, Paint paint)

// 對於字符數組char[]
// 截取文本使用起始位置(index)和長度(count)
    public void drawText (char[] text, int index, int count, float x, float y, Paint paint)

// 實例:繪製從位置1-3的文本
canvas.drawText("abcdefg",1,4,300,400,mPaint1);

        // 字符數組情況
        // 字符數組(要繪製的內容)
        char[] chars = "abcdefg".toCharArray();

        // 參數爲 (字符數組 起始座標 截取長度 基線x 基線y 畫筆)
        canvas.drawText(chars,1,3,200,500,textPaint);
        // 效果同上

情況2:分別指定文本的位置

// 參數text:繪製的文本
// 參數pos:數組類型,存放每個字符的位置(座標)
// 注意:必須指定所有字符位置
 public void drawPosText (String text, float[] pos, Paint paint)

// 對於字符數組char[],可以截取部分文本進行繪製
// 截取文本使用起始位置(index)和長度(count)
    public void drawPosText (char[] text, int index, int count, float[] pos, Paint paint)

// 特別注意:
// 1. 在字符數量較多時,使用會導致卡頓
// 2. 不支持emoji等特殊字符,不支持字形組合與分解

  // 實例
  canvas.drawPosText("abcde", new float[]{
                100, 100,    // 第一個字符位置
                200, 200,    // 第二個字符位置
                300, 300,    // ...
                400, 400,
                500, 500
        }, mPaint1)// 數組情況(繪製部分文本)
       char[] chars = "abcdefg".toCharArray();

        canvas.drawPosText(chars, 1, 3, new float[]{
                300, 300,    // 指定的第一個字符位置
                400, 400,    // 指定的第二個字符位置
                500, 500,    // 指定的第三個字符位置

        }, mPaint1);

情況3:指定路徑,並根據路徑繪製文字

// 在路徑(540,750,640,450,840,600)寫上"在Path上寫的字:Carson_Ho"字樣
        // 1.創建路徑對象
        Path path = new Path();
        // 2. 設置路徑軌跡
        path.cubicTo(540, 750, 640, 450, 840, 600);
         // 3. 畫路徑
        canvas.drawPath(path,mPaint2);
        // 4. 畫出在路徑上的字
        canvas.drawTextOnPath("畫出在路徑上的字", path, 50, 0, mPaint2);
      
4.2.4 繪製圖片

繪製圖片分爲:繪製矢量圖(drawPicture)和繪製位圖(drawBitmap)

繪製矢量圖(drawPicture)

  • 作用:繪製矢量圖的內容,即繪製存儲在矢量圖裏某個時刻Canva繪製內容的操作。

矢量圖(Picture)的作用:存儲某個時刻Canvas繪製內容得操作

  • 應用場景:繪製之前繪製過的內容
  1. 相比於再次調用各種繪圖API,使用Picture能節省操作和時間
  2. 如果不手動調用,錄製的內容不會顯示在屏幕上,只是存儲起來

特別注意:使用繪製矢量圖前請關閉硬件加速,以免引起不必要的問題!

  • 具體使用
// 獲取寬度
Picture.getWidth ()// 獲取高度
Picture.getHeight ()

// 開始錄製 
// 即將Canvas中所有的繪製內容存儲到Picture中
// 返回一個Canvas
Picture.beginRecording(int width, int height)

// 結束錄製
Picture.endRecording ()

// 將Picture裏的內容繪製到Canvas中
Picture.draw (Canvas canvas)

// 還有兩種方法可以將Picture裏的內容繪製到Canvas中
// 方法2:Canvas.drawPicture()
// 方法3:將Picture包裝成爲PictureDrawable,使用PictureDrawable的draw方法繪製。

// 下面會詳細介紹
  • 一般使用的具體步驟
// 步驟1:創建Picture對象
Picture mPicture = new Picture();

// 步驟2:開始錄製 
mPicture.beginRecording(int width, int height);

// 步驟3:繪製內容 or 操作Canvas
canvas.drawCircle(500,500,400,mPaint);
...(一系列操作)

// 步驟4:結束錄製
mPicture.endRecording ();

步驟5:某個時刻將存儲在Picture的繪製內容繪製出來
mPicture.draw (Canvas canvas);
  • 實例介紹
    將座標系移動到(450,650);繪製一個圓,將上述Canvas操作錄製下來,並在某個時刻出來。

步驟1:創建Picture對象

Picture mPicture = new Picture();

步驟2:開始錄製

Canvas recordingCanvas = mPicture.beginRecording(500, 500);

// 注:要創建Canvas對象來接收beginRecording()返回的Canvas對象

步驟3:繪製內容/操作Canvas

        // 位移
        // 將座標系的原點移動到(450,650)
        recordingCanvas.translate(450,650);

        // 記得先創建一個畫筆
        Paint paint = new Paint();
        paint.setColor(Color.BLUE);
        paint.setStyle(Paint.Style.FILL);

        // 繪製一個圓
        // 圓心爲(0,0),半徑爲100
       recordingCanvas.drawCircle(0,0,100,paint);

步驟4:結束錄製

mPicture.endRecording();

步驟5:將存儲在Picture的繪製內容繪製出來
有三種方法:

Picture.draw (Canvas canvas)

Canvas.drawPicture()

PictureDrawable.draw()

主要區別如下:

主要區別/類型 是否對Canvas狀態(clip、Matrix)有影響 對繪製結果可控程度
Picture.draw()
Canvas.drawPicture()
PictureDrawable.draw()

繪製位圖(drawBitmap)

  • 作用:將已有的圖片轉換爲位圖(Bitmap),最後再繪製到Canvas上

位圖,即平時我們使用的圖片資源

  • 獲取BIgmap對象的方式

要繪製Bitmap,就要先獲取Bitmap對象,具體獲取方式如下:
獲取Bitmap對象方式
通過BitmapFactory獲取Bitmap(從不同位置獲取)

// 共3個位置:資源文件、內存卡、網絡

// 位置1:資源文件(drawable/mipmap/raw)
        Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(),R.raw.bitmap);

// 位置2:資源文件(assets)
        Bitmap bitmap=null;
        try {
            InputStream is = mContext.getAssets().open("bitmap.png");
            bitmap = BitmapFactory.decodeStream(is);
            is.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

// 位置3:內存卡文件
    Bitmap bitmap = BitmapFactory.decodeFile("/sdcard/bitmap.png");

// 位置4:網絡文件:
// 省略了獲取網絡輸入流的代碼
        Bitmap bitmap = BitmapFactory.decodeStream(is);
        is.close();

繪製Bitmap

// 方法1
// 注:圖片左上角位置默認爲座標原點。
    public void drawBitmap (Bitmap bitmap, Matrix matrix, Paint paint)

 // 方法2
 // 參數 left、top指定了圖片左上角的座標(距離座標原點的距離):
    public void drawBitmap (Bitmap bitmap, float left, float top, Paint paint)

// 方法3
// 參數(src,dst) = 兩個矩形區域
// Rect src:指定需要繪製圖片的區域(即要繪製圖片的哪一部分)
// Rect dst 或RectF dst:指定圖片在屏幕上顯示(繪製)的區域
    public void drawBitmap (Bitmap bitmap, Rect src, Rect dst, Paint paint)

// 方法4
    public void drawBitmap (Bitmap bitmap, Rect src, RectF dst, Paint paint)

方法3、4應用場景:實現動態效果

動態效果 = 逐漸繪製圖形部分

4.2.5 繪製路徑
// 通過傳入具體路徑Path對象 & 畫筆
canvas.drawPath(mPath, mPaint)
4.2.6 畫布操作
  • 作用:改變畫布的性質

改變後,任何的後續操作都會受到影響

  1. 畫布變換

平移(translate)

  • 作用:移動畫布(實際上是移動座標系,如下圖)
  • 具體使用

// 將畫布原點向右移200px,向下移100px
canvas.translate(200, 100)  
// 注:位移是基於當前位置移動,而不是每次都是基於屏幕左上角的(0,0)點移動

在這裏插入圖片描述
縮放(scale)

  • 作用:放大/縮小 畫布的倍數
  • 具體使用:
// 共有兩個方法
// 方法1
// 以(px,py)爲中心,在x方向縮放sx倍,在y方向縮放sy倍
// 縮放中心默認爲(0,0)
public final void scale(float sx, float sy)     

// 方法2
// 比方法1多了兩個參數(px,py),用於控制縮放中心位置
// 縮放中心爲(px,py)
 public final void scale (float sx, float sy, float px, float py)

當縮放倍數爲負數時,會先進行縮放,然後根據不同情況進行圖形翻轉
假設縮放倍數爲(a,b) ,旋轉中心爲(px,py)

旋轉方式 a>0 a<0
b>0 \ 以px爲軸翻轉
b<0 以py爲軸翻轉 以旋轉中心翻轉

具體如下圖:(縮放倍數爲1.5,旋轉中心爲(0,0)爲例)
在這裏插入圖片描述
旋轉(rotate)

  • 注意:角度增加方向爲順時針
  • 具體使用:
// 方法1
// 以原點(0,0)爲中心旋轉 degrees 度
public final void rotate(float degrees)  
  // 以原點(0,0)爲中心旋轉 90 度
canvas.rotate(90);

// 方法2
// 以(px,py)點爲中心旋轉degrees度
public final void rotate(float degrees, float px, float py)  
// 以(30,50)爲中心旋轉 90 度
canvas.rotate(90,30,50);                

錯切(skew)

  • 作用:將畫布在x方向傾斜a角度,在y方向傾斜b角度
  • 具體使用:

// 參數 sx = tan a ,sx>0時表示向X正方向傾斜(即向左)
// 參數 sy = tan b ,sy>0時表示向Y正方向傾斜(即向下)
public void skew(float sx, float sy)   


// 實例
   // 爲了方便觀察,我將座標系移到屏幕中央
        canvas.translate(300, 500);
        // 初始矩形
        canvas.drawRect(20, 20, 400, 200, mPaint2);

        // 向X正方向傾斜45度
        canvas.skew(1f, 0);
        canvas.drawRect(20, 20, 400, 200, mPaint1);
        
        //向X負方向傾斜45度
        canvas.skew(-1f, 0);
        canvas.drawRect(20, 20, 400, 200, mPaint1);
        
        // 向Y正方向傾斜45度
        canvas.skew(0, 1f);
        canvas.drawRect(20, 20, 400, 200, mPaint1);

       // 向Y負方向傾斜45度
        canvas.skew(0, -1f);
        canvas.drawRect(20, 20, 400, 200, mPaint1);

在這裏插入圖片描述
2. 畫布裁剪

特別注意:其餘的區域只是不能編輯,但是並沒有消失。

  • 具體使用
裁剪共分爲:裁剪路徑、裁剪矩形、裁剪區域

// 裁剪路徑
// 方法1
public boolean clipPath(@NonNull Path path)
// 方法2
public boolean clipPath(@NonNull Path path, @NonNull Region.Op op)


// 裁剪矩形
// 方法1
public boolean clipRect(int left, int top, int right, int bottom)
// 方法2
public boolean clipRect(float left, float top, float right, float bottom)
// 方法3
public boolean clipRect(float left, float top, float right, float bottom,
            @NonNull Region.Op op) 

// 裁剪區域
// 方法1
public boolean clipRegion(@NonNull Region region)
// 方法2
public boolean clipRegion(@NonNull Region region, @NonNull Region.Op op)

這裏特別說明一下參數Region.Op op
作用:在剪下多個區域下來的情況,當這些區域有重疊的時候,這個參數決定重疊部分該如何處理,多次裁剪之後究竟獲得了哪個區域,有以下幾種參數:
在這裏插入圖片描述
3. 畫布快照
這裏先理清幾個概念

  • 畫布狀態:當前畫布經過的一系列操作
  • 狀態棧:存放畫布狀態和圖層的棧(後進先出)
    在這裏插入圖片描述
  • 畫布的構成:有多個圖層構成,如下圖:
  1. 在畫布上操作=在圖層上操作
  2. 如無設置,繪製操作和畫布操作是默認圖層上進行
  3. 在通常情況下,使用默認圖層就可滿足需求;若需要繪製複雜的內容(如地圖)使用更多的圖層
  4. 最終顯示的結果=所有圖層疊在一起的效果
    在這裏插入圖片描述

保存當前畫布狀態(save)

  • 作用:保存畫布狀態(即保存畫布的一系列操作)
  • 應用場景:畫布的操作是不可逆的,而且會影響後續的步驟,假如需要回到之前畫布進行下一次操作,就需要對畫布的狀態進行保存和回滾
  • 具體使用:

// 方法1:
  // 保存全部狀態
  public int save ()

// 方法2:
  // 根據saveFlags參數保存一部分狀態
  // 使用該參數可以只保存一部分狀態,更加靈活
  public int save (int saveFlags)

// saveFlags參數說明:
// 1.ALL_SAVE_FLAG(默認):保存全部狀態
// 2. CLIP_SAVE_FLAG:保存剪輯區
// 3. CLIP_TO_LAYER_SAVE_FLAG:剪裁區作爲圖層保存
// 4. FULL_COLOR_LAYER_SAVE_FLAG:保存圖層的全部色彩通道
// 5. HAS_ALPHA_LAYER_SAVE_FLAG:保存圖層的alpha(不透明度)通道
// 6. MATRIX_SAVE_FLAG:保存Matrix信息(translate, rotate, scale, skew)

// 每調用一次save(),都會在棧頂添加一條狀態信息(入棧)

保存某個圖層狀態(saveLayer)

  • 作用:新建一個圖層,並放入特定的棧中
  • 具體使用

使用起來非常複雜,因爲圖層之間疊加會導致計算量成倍增長,應儘量避免使用

// 無圖層alpha(不透明度)通道
public int saveLayer (RectF bounds, Paint paint)
public int saveLayer (RectF bounds, Paint paint, int saveFlags)
public int saveLayer (float left, float top, float right, float bottom, Paint paint)
public int saveLayer (float left, float top, float right, float bottom, Paint paint, int saveFlags)

// 有圖層alpha(不透明度)通道
public int saveLayerAlpha (RectF bounds, int alpha)
public int saveLayerAlpha (RectF bounds, int alpha, int saveFlags)
public int saveLayerAlpha (float left, float top, float right, float bottom, int alpha)
public int saveLayerAlpha (float left, float top, float right, float bottom, int alpha, int saveFlags)

回滾上一次保存的狀態(restore)

  • 作用:恢復上一次保存的畫布狀態
  • 具體使用
// 採取狀態棧的形式。即從棧頂取出一個狀態進行恢復。
canvas.restore();

回滾指定保存的狀態(restoreToCount)

  • 作用:恢復指定狀態。將指定位置以及以上所有狀態出棧
  • 具體使用:
 canvas.restoreToCount(3)// 彈出 3、4、5的狀態,並恢復第3次保存的畫布狀態

在這裏插入圖片描述
獲取保存的次數(getSaveCount)

  • 作用:獲取保存過圖層的次數
  • 具體使用:
canvas.getSaveCount();
// 以上面棧爲例,則返回5
// 注:即使彈出所有的狀態,返回值依舊爲1,代表默認狀態。(返回值最小爲1)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章