Android 2D Graphics學習(二)、Canvas篇1、Canvas基本使用

yangxi_001發表於2013-12-24
Canvas的意思是畫布,表現在螢幕上就是一塊區域,我們可以再上面使用各種API繪製我們想要的東西。可以說,Canvas貫穿整個2D Graphics,android.graphics中的所有類,幾乎都於Canvas有直接或間接的聯絡。所以瞭解Canvas是學習2D Graphics的基礎。

Android官方文件對Canvas的簡介很好的介紹了Canvas的使用:

[java] view plaincopy
  1. The Canvas class holds the "draw" calls. To draw something, you need 4 basic components: A Bitmap to hold the pixels,  
  2.  a Canvas to host the draw calls (writing into the bitmap), a drawing primitive (e.g. Rect, Path, text, Bitmap),   
  3. and a paint (to describe the colors and styles for the drawing).   
一個Canvas物件有四大基本要素:

1、一個用來儲存畫素的Bitmap

2、一個Canvas在Bitmap上進行繪製操作

3、繪製的東西

4、繪製的畫筆Paint


1、如何獲得一個Canvas物件。

Canvas物件的獲取方式有三種:

第一種我們通過重寫View.onDraw方法,View中的Canvas物件會被當做引數傳遞過來,我們操作這個Canvas,效果會直接反應在View中。

第二種就是當你想自己建立一個Canvas物件。從上面的基本要素可以明白,一個Canvas物件一定是結合了一個Bitmap物件的。所以一定要為一個Canvas物件設定一個Bitmap物件。

[java] view plaincopy
  1. //得到一個Bitmap物件,當然也可以使用別的方式得到。但是要注意,改bitmap一定要是mutable(異變的)  
  2.         Bitmap b = Bitmap.createBitmap(100,100, Bitmap.Config.ARGB_8888);  
  3.         Canvas c = new Canvas(b);  
  4.         /*先new一個Canvas物件,在呼叫setBitmap方法,一樣的效果 
  5.          * Canvas c = new Canvas(); 
  6.          * c.setBitmap(b); 
  7.          */  
第三種方式,是呼叫SurfaceHolder.lockCanvas(),返回一個Canvas物件。


2、Canvas能繪製什麼

Canvas類提供了一系列的draw...方法,從這些方法的名字就可以知道Canvas可以繪製的物件。

1、填充

[java] view plaincopy
  1. public void drawARGB(int a, int r, int g, int b)  
  2. public void drawColor(int color)  
  3. public void drawRGB(int r, int g, int b)  
  4. public void drawColor(int color, PorterDuff.Mode mode)  
因為Canvas內部維持了一個mutable Bitmap,所以,它可以使用這些顏色去填充整個Bitmap。並且在API中提到(restricted to the current clip)受限制於clip的範圍


[java] view plaincopy
  1.  public void drawPaint(Paint paint)  

同理,Canvas也可以使用畫筆去填充整個Bitmap,同樣和填充顏色一樣受限制於clip的範圍,API中明確指出(This is equivalent (but faster) to drawing an
 infinitely large rectangle with the specified paint)這相當於用指定的畫筆畫一個更大範圍的矩形,但是速度更快。

其實在Skia內部,填充呼叫的都是drawPaint方法的。



2、繪製幾何影象

canvas.drawArc (扇形)

canvas.drawCircle(圓)

canvas.drawOval(橢圓)

canvas.drawLine(線)

canvas.drawPoint(點)

canvas.drawRect(矩形)

canvas.drawRoundRect(圓角矩形)

canvas.drawVertices(頂點)

cnavas.drawPath(路徑)


3、繪製圖片

canvas.drawBitmap (點陣圖)

canvas.drawPicture (圖片)


4、文字

canvas.drawText


上面列舉的是Canvas所能繪製的基本內容,在實際使用中,可以使用各種過濾或者過度模式,或者其他手段,來達到繪製各種效果。


3、Canvas的變換

如果只是那些簡單的draw...方法,那麼canvas的功能就太單調了。Canvas還提供了一系列位置轉換的方法:rorate、scale、translate、skew(扭曲)等。

  1. @Override  
  2.         protected void onDraw(Canvas canvas) {  
  3.             canvas.translate(100, 100);  
  4.             canvas.drawColor(Color.RED);//可以看到,整個螢幕依然填充為紅色  
  5.               
  6.             canvas.drawRect(new Rect(-100, -100, 0, 0), new Paint());//縮放了  
  7.             canvas.scale(0.5f, 0.5f);  
  8.             canvas.drawRect(new Rect(0, 0, 100, 100), new Paint());  
  9.               
  10.             canvas.translate(200, 0);  
  11.             canvas.rotate(30);  
  12.             canvas.drawRect(new Rect(0, 0, 100, 100), new Paint());//旋轉了  
  13.               
  14.             canvas.translate(200, 0);  
  15.             canvas.skew(.5f, .5f);//扭曲了  
  16.             canvas.drawRect(new Rect(0, 0, 100, 100), new Paint());  
  17.             // canvas.setMatrix(matrix);//Matrix的使用在後面在是。  
  18.         }  


Canvas雖然內部保持了一個Bitmap,但是它本身並不代表那個Bitmap,而更像是一個圖層。我們對這個圖層的平移旋轉和縮放等等操作,並不影響內部的Bitmap,僅僅是改變了該圖層相對於內部Bitmap 的座標位置、比例和方向而已。


4、Canvas的儲存和回滾

為了方便一些轉換操作,Canvas還提供了儲存和回滾屬性的方法(save和restore),比如你可以先儲存目前畫紙的位置(save),然後旋轉90度,向下移動100畫素後畫一些圖形,畫完後呼叫restore方法返回到剛才儲存的位置。

Canvas提供的該功能的API如下:

[java] view plaincopy
  1. /** 
  2.      * 儲存當前的matrix和clip到私有的棧中(Skia內部實現)。任何matrix變換和clip操作都會在呼叫restore的時候還原。 
  3.      * @return 返回值可以傳入到restoreToCount()方法,以返回到某個save狀態之前。 
  4.      */  
  5.     public native int save();  
  6.       
  7.   
  8.   
  9.     /** 
  10.      * 傳入一個標誌,來表示當restore 的時候,哪些引數需要還原。該引數定義在Canvas中,參照下面。 
  11.      * save()方法預設的是還原matrix和clip,但是可以使用這個方法指定哪些需要還原。並且只有指定matrix和clip才有效,其餘的幾個引數是 
  12.      * 用於saveLayer()和saveLayerAlpha()方法 的。 
  13.      */  
  14.     public native int save(int saveFlags);  
  15.   
  16.   
  17.     /** 
  18.      * 回到上一個save呼叫之前的狀態,如果restore呼叫的次數大於save方法,會出錯。 
  19.      */  
  20.     public native void restore();  
  21.   
  22.      /** 
  23.      * 返回棧中儲存的狀態,值等譯 save()呼叫次數-restore()呼叫次數 
  24.      */  
  25.     public native int getSaveCount();  
  26.   
  27.   
  28.       
  29.   
  30.     /** 
  31.      * 回到任何一個save()方法呼叫之前的狀態 
  32.      */  
  33.     public native void restoreToCount(int saveCount);  
  34.   
  35.   
  36.   
  37. /**saveFlags的引數*/  
  38.  public static final int MATRIX_SAVE_FLAG = 0x01;//需要還原Matrix  
  39.     public static final int CLIP_SAVE_FLAG = 0x02;//需要還原Clip  
  40. /**下面三個引數在saveLayer的時候使用,具體作用,沒有搞明白*/  
  41.    public static final int HAS_ALPHA_LAYER_SAVE_FLAG = 0x04;  
  42.   public static final int FULL_COLOR_LAYER_SAVE_FLAG = 0x08;  
  43.   public static final int CLIP_TO_LAYER_SAVE_FLAG = 0x10;  
  44.     public static final int ALL_SAVE_FLAG = 0x1F//還原所有  
  45.   
  46. /*關於saveLayer的具體flags還不大明白它的含義,具體怎麼使用在下面例子中*/  
  47.  public int saveLayer(RectF bounds, Paint paint, int saveFlags)  
  48. public int saveLayer(float left, float top, float right, float bottom,  
  49.                          Paint paint, int saveFlags)   
  50.  public int saveLayerAlpha(RectF bounds, int alpha, int saveFlags)  
  51. public int saveLayerAlpha(float left, float top, float right, float bottom,  
  52.                               int alpha, int saveFlags)  



saveLayer

Canvas 在一般的情況下可以看作是一張畫布,所有的繪圖操作如drawBitmap, drawCircle都發生在這張畫布上,這張畫板還定義了一些屬性比如Matrix,顏色等等。但是如果需要實現一些相對複雜的繪圖操作,比如多層動畫,地圖(地圖可以有多個地圖層疊加而成,比如:政區層,道路層,興趣點層)。Canvas提供了圖層(Layer)支援,預設情況可以看作是隻有一個圖層Layer。如果需要按層次來繪圖,Android的Canvas可以使用SaveLayerXXX, Restore 來建立一些中間層,對於這些Layer是按照“棧結構“來管理的:       


 建立一個新的Layer到“棧”中,可以使用saveLayer, savaLayerAlpha, 從“棧”中推出一個Layer,可以使用restore,restoreToCount。但Layer入棧時,後續的DrawXXX操作都發生在這個Layer上,而Layer退棧時,就會把本層繪製的影象“繪製”到上層或是Canvas上,在複製Layer到Canvas上時,可以指定Layer的透明度(Layer),這是在建立Layer時指定的:public int saveLayerAlpha(RectF bounds, int alpha, int saveFlags)本例Layers 介紹了圖層的基本用法:Canvas可以看做是由兩個圖層(Layer)構成的,為了更好的說明問題,我們將程式碼稍微修改一下,預設圖層繪製一個紅色的圓,在新的圖層畫一個藍色的圓,新圖層的透明度為0×88。      

[java] view plaincopy
  1. public class Layers extends Activity {  
  2.   
  3.     @Override  
  4.     protected void onCreate(Bundle savedInstanceState) {  
  5.         super.onCreate(savedInstanceState);  
  6.         setContentView(new SampleView(this));  
  7.     }  
  8.   
  9.     private static class SampleView extends View {  
  10.         private static final int LAYER_FLAGS = Canvas.MATRIX_SAVE_FLAG | Canvas.CLIP_SAVE_FLAG  
  11.                 | Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.FULL_COLOR_LAYER_SAVE_FLAG  
  12.                 | Canvas.CLIP_TO_LAYER_SAVE_FLAG;  
  13.   
  14.         private Paint mPaint;  
  15.   
  16.         public SampleView(Context context) {  
  17.             super(context);  
  18.             setFocusable(true);  
  19.   
  20.             mPaint = new Paint();  
  21.             mPaint.setAntiAlias(true);  
  22.         }  
  23.   
  24.         @Override  
  25.         protected void onDraw(Canvas canvas) {  
  26.             canvas.drawColor(Color.WHITE);    
  27.             canvas.translate(1010);    
  28.             mPaint.setColor(Color.RED);    
  29.             canvas.drawCircle(757575, mPaint);    
  30.             canvas.saveLayerAlpha(002002000x88, LAYER_FLAGS);    
  31.             mPaint.setColor(Color.BLUE);    
  32.             canvas.drawCircle(12512575, mPaint);    
  33.             canvas.restore();   
  34.          }  
  35.     }  
  36. }  

相關文章