Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> canvas的常見用法

canvas的常見用法

編輯:關於Android編程

Canvas

canvas是一種抽象概念,是2D圖形系統中的重要部分,canvas一系列函數最終都是android 2D圖形庫Skia的一些列封裝,對應在SKCanvas.cpp。canvas在系統中的位置如下圖所示

\

可以將canvas看成一個透明的圖層,使用canvas之後會產生一個透明圖層,然後在這個新圖層上畫圖,畫完之後覆蓋在屏幕上顯示,疊加。
比較經典的例子就是

` protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    //構造一個矩形
    Rect rect1 = new Rect(0, 0, 400, 220);
    //在平移畫布前用綠色畫下邊框
    canvas.drawRect(rect1, paint_green);

    //平移畫布後,再用紅色邊框重新畫下這個矩形
    canvas.translate(100, 100);
    canvas.drawRect(rect1, paint_red);
}`

我們首先畫了一個綠色矩形框,然後將canvas平移了,接著畫了一個紅色的矩形框,結果如下

\

這裡我們會發現,平移了canvas之後綠色矩形框沒發生變化!,拉近鏡頭我們仔細看看究竟發生了什麼,如何印證canvas每次會產生一個透明圖層?

調用canvas.drawRect(rect1, paint_green);時,產生一個Canvas透明圖層,由於當時還沒有對坐標系平移,所以坐標原點是(0,0);再在系統在Canvas上畫好之後,覆蓋到屏幕上顯示出來,過程如下圖(圖片來自網絡,鏈接在文後):

然後再第二次調用canvas.drawRect(rect1, paint_red);時,又會重新產生一個全新的Canvas畫布,此時由於使用tranlate移動了畫布
因而在畫圖時是以新原點來產生視圖的,然後合成到屏幕上,超出部分不顯示,最後就是我們看到結果了。

canvas常用方法

\

下面來清點一下重要的API,繪制顏色就不贅述了

繪制基本形狀

drawRoundRecf畫圓角矩形

`   // 第一種
    RectF rectF = new RectF(100,100,400,400);
    canvas.drawRoundRect(rectF,30,30,paint_red);

    // 第二種 需要api21,一般常用第一種
   // canvas.drawRoundRect(100,100,800,400,30,30,paint_red);`

\

這裡是采用第一種方法畫出來的,參數30(rx),30(ry)是橢圓的兩個半徑,用來確定圓角的弧度。

drawOval畫橢圓

`   // 第一種
    RectF rectF = new RectF(100,100,500,400);
    canvas.drawOval(rectF,paint_red);

    // 第二種
    canvas.drawOval(100,100,800,400,paint_red);`

通常也是使用第一種,畫橢圓只需要一個矩形即可,橢圓是改矩形的內切

\

drawArc畫圓弧<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxibG9ja3F1b3RlPg0KCTxwPi8vILXa0rvW1jxiciAvPg0KCXB1YmxpYyB2b2lkIGRyYXdBcmMoQE5vbk51bGwgUmVjdEYgb3ZhbCwgZmxvYXQgc3RhcnRBbmdsZSwgZmxvYXQgc3dlZXBBbmdsZSwgYm9vbGVhbiB1c2VDZW50ZXIsIEBOb25OdWxsIFBhaW50IHBhaW50KXt9PC9wPg0KCTxwPi8vILXatv7W1jxiciAvPg0KCXB1YmxpYyB2b2lkIGRyYXdBcmMoZmxvYXQgbGVmdCwgZmxvYXQgdG9wLCBmbG9hdCByaWdodCwgZmxvYXQgYm90dG9tLCBmbG9hdCBzdGFydEFuZ2xlLGZsb2F0IHN3ZWVwQW5nbGUsIGJvb2xlYW4gdXNlQ2VudGVyLCBATm9uTnVsbCBQYWludCBwYWludCkge308L3A+DQo8L2Jsb2NrcXVvdGU+DQo8cD6/ydLUv7Sz9tXiwO/KudPDwcvN1tSytcTQzte0o6yz/bTL1q7N4rzTyc/By8j9uPayzsr9PC9wPg0KPGJsb2NrcXVvdGU+DQoJPHA+c3RhcnRBbmdsZSAvLyC/qsq8vce2yDwvcD4NCgk8cD5zd2VlcEFuZ2xlIC8vIMmouf29x7bIPC9wPg0KCTxwPnVzZUNlbnRlciAvLyDKx7fxus3W0NDEtePBrLPJ0ru49rfisdW1xM280M48L3A+DQo8L2Jsb2NrcXVvdGU+DQo8cHJlIGNsYXNzPQ=="brush:java;"> ` RectF rectF = new RectF(100, 100, 400, 400); RectF rectF1 = new RectF(200, 200, 500, 500); canvas.drawArc(rectF, 0, 40, true, paint_green); canvas.drawArc(rectF1, 0, 40, false, paint_green);`

\

畫圓弧要清楚,0-40畫弧,首先水平那根線是起點,按順時針40度停止。

drawPath

這個結合path一起使用會非常強大!(path用法也是內涵滿滿,這裡就不展開敘述了)

這裡看下canvas中的用法

public void drawPath(@NonNull Path path, @NonNull Paint paint){}

傳入路徑,和對應的畫筆即可

`   Path path = new Path();
    path.moveTo(50,50);
    path.quadTo(30,220,320,450);

    canvas.drawPath(path,paint_green);`

這裡使用path畫了一條貝塞爾曲線

\

畫布裁剪

裁剪涉及到一個Region.Op區域組合的問題

`    假設用region A  去組合region B   
public enum Op {  
        DIFFERENCE(0), //A和B的差集范圍,即A - B,只有在此范圍內的繪制內容才會被顯示;
        INTERSECT(1), // 即A和B的交集范圍,只有在此范圍內的繪制內容才會被顯示
        UNION(2),      //即A和B的並集范圍,即兩者所包括的范圍的繪制內容都會被顯示;
        XOR(3),        //A和B的補集范圍,此例中即A除去B以外的范圍,只有在此范圍內的繪制內容才會被顯示;
        REVERSE_DIFFERENCE(4), //B和A的差集范圍,即B - A,只有在此范圍內的繪制內容才會被顯示;
        REPLACE(5); //不論A和B的集合狀況,B的范圍將全部進行顯示,如果和A有交集,則將覆蓋A的交集范圍;
 }  `

clipPath( ),clipRect( ),clipRegion( );通過Path,Rect,Region的不同組合,幾乎可以支持任意形狀的裁剪區域!

這裡演示一個Region.Op.DIFFERENCE,將畫筆改為FILL,然後

`   canvas.clipRect(10, 10, 110, 110);        //第一個
    canvas.clipRect(50, 50, 150, 150, Region.Op.DIFFERENCE); //第二個
    canvas.drawRect(0, 0, 200, 200, paint_green);`

\

畫布狀態

save():把當前狀態的狀態進行保存,然後放入棧中

restore():把棧頂畫布狀態取出

 

畫布變換

畫布變換主要包括translate(位移)、scale(縮放)、rotate(旋轉)、skew(傾斜),畫布操作可以幫助我們更加容易的方式制作圖形。

【位移translate】

public void translate(float dx, float dy)

基於當前坐標系的移動,並不是屏幕左上角的原點位置

` //構造一個矩形
    Rect rect1 = new Rect(0, 0, 200, 100);
    canvas.translate(50, 50);
    //在平移畫布前用綠色畫下邊框
    canvas.drawRect(rect1, paint_green);

    //平移畫布後,再用紅色邊框重新畫下這個矩形
    canvas.translate(50, 50);
    canvas.drawRect(rect1, paint_red);`

\

【縮放scale】

public void scale (float sx, float sy),分別是x,y軸的縮放比例

public final void scale (float sx, float sy, float px, float py),x.y軸的縮放比例,px,py表示縮放中心位置

其中當縮放比例為負數時候會根據縮放中心軸進行翻轉

套用網上一個經典的例子(畫筆要設置粗一點,不然會有部分顯示不全)

` canvas.translate(mWidth/2,mHeight/2);

    RectF rectf = new RectF(-300,-300,300,300);
    for (int i=0;i<15;i++){
        canvas.scale(0.8f,0.8f);
        canvas.drawRect(rectf,paint_red);
    }`

\

【旋轉 rotate】

public void rotate (float degrees),旋轉角度(順時針)

public final void rotate (float degrees, float px, float py),旋轉角度和控制點

這個在畫表盤啥的很常用。同樣跟位移一樣,旋轉度數也是可以疊加的。

【錯切 skew】

public void skew (float sx, float sy)

float sx:將畫布在x方向上傾斜相應的角度,sx傾斜角度的tan值,
float sy:將畫布在y軸方向上傾斜相應的角度,sy為傾斜角度的tan值.

`Rect rect1 = new Rect(10,10,200,100);

    canvas.drawRect(rect1, paint_green);
    canvas.skew(1,0);//X軸傾斜45度,Y軸不變
    canvas.drawRect(rect1, paint_red);`

\

繪制文本

普通水平繪制drawText

這個比較簡單,但是需要注意繪制text繪制精確位置使用FontMetrics,主要包含四個參數

ascent = ascent線的y坐標 - baseline線的y坐標;

descent = descent線的y坐標 - baseline線的y坐標;

top = top線的y坐標 - baseline線的y坐標;

bottom = bottom線的y坐標 - baseline線的y坐標;

\

指定每個文字位置

void drawPosText (char[] text, int index, int count, float[] pos, Paint paint)

void drawPosText (String text, float[] pos, Paint paint)

參數說明

char[] text:要繪制的文字數組

int index::第一個要繪制的文字的索引

int count:要繪制的文字的個數,用來算最後一個文字的位置,從第一個繪制的文字開始算起

float[] pos:每個字體的位置,同樣兩兩一組,如{x1,y1,x2,y2,x3,y3……}

`float []pos=new float[]{80,100,
            100,200,
            120,300,
            140,400};
    canvas.drawPosText("1234", pos, paint);`

\

··

沿路徑繪制

void drawTextOnPath (String text, Path path, float hOffset, float vOffset, Paint paint)
void drawTextOnPath (char[] text, int index, int count, Path path, float hOffset, float vOffset, Paint paint)

參數說明:

float hOffset : 與路徑起始點的水平偏移距離

float vOffset : 與路徑中心的垂直偏移量

` String string = "測試文字偏移的參數";

    Path circlePath = new Path();
    circlePath.addCircle(220, 200, 100, Path.Direction.CCW);
    canvas.drawPath(circlePath, paint_red);//繪制出路徑原形

    Path circlePath2 = new Path();
    circlePath2.addCircle(550, 200, 100, Path.Direction.CCW);
    canvas.drawPath(circlePath2, paint_red);//繪制出路徑原形

    paint_green.setTextSize(30);

     //hoffset、voffset參數值全部設為0,看原始狀態是怎樣的
    canvas.drawTextOnPath(string, circlePath, 0, 0, paint_green);
    //第二個路徑,改變hoffset、voffset參數值
    canvas.drawTextOnPath(string, circlePath2, 80, 30, paint_green);`

\

常用的基本介紹差不多了還有諸如

drawBitmapMesh:只對繪制的Bitmap作用,使其變形drawVertices:使得畫布變形等等實在撸不動了。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved