Android官方源碼中對(duì)Canvas的描述是:“Canvas類容納所有和Draw(繪制)相關(guān)方法。為了去Draw些東西,你需要具備4個(gè)基礎(chǔ)要素:1個(gè)Bitmap用來承載像素信息,1個(gè)Canvas用來管理Draw相關(guān)方法(寫入Bitmap中),1個(gè)繪圖基元(例如,Rect,Path,text,Bitmap),1個(gè)畫筆(用于描繪圖像的顏色和風(fēng)格)。
這和我們?nèi)粘@斫獾睦L畫異曲同工,Bitmap作為畫布,Canvas管理著繪畫的手法,繪圖基元代表著要繪制的目標(biāo),Paint就是你手里的畫筆和顏料。
如何得到1個(gè)Canvas對(duì)象
- 之前提到的onDraw方法的入口參數(shù)就是Canvas,我們用變量承載它,就可以使用,而我們操作這個(gè)Canvas最終的效果會(huì)直接反應(yīng)在這個(gè)View上。
- SurfaceView是View的繼承了,其內(nèi)部有專門的線程來完成畫圖的工作,而不用像View一樣需要等待刷新,主要用在游戲和高品質(zhì)動(dòng)畫方面。既然是View的繼承類,SurfaceView自然可以獲取到Canvas的對(duì)象,方式是通過調(diào)用SurfaceView的好基友SurfaceHolder的lockCanvas()方法。
- 當(dāng)然,除了獲取View或SurfaceView自帶的現(xiàn)成的Canvas對(duì)象,我們還可以自己創(chuàng)建。從4大基本要素我們就可以知道,1個(gè)Canvas對(duì)象一定要結(jié)合1個(gè)Bitmap對(duì)象。所以一定要為新建的Canvas對(duì)象設(shè)置1個(gè)Bitmap對(duì)象。
/**
* 得到一個(gè)Bitmap對(duì)象,當(dāng)然也可以使用別的方式得到。但是要注意,改bitmap一定要是mutable(異變的)
* mutable : 易變的,不定的
* mutable 作用 : 控制bitmap的setPixel方法能否使用,也就是外界能否修改bitmap的像素。
* Bitmap.createBitmap(mWidth, mHeight, Config.ARGB_8888) 為 mutable 為true
* BimapFactory.decodeResource() 得到的mutable 為false, 要想其為true
* 一般會(huì)BimtapFactory.decodeResource().copy(configu_argb_8888, true);
* 先new一個(gè)Canvas對(duì)象,在調(diào)用setBitmap方法,一樣的效果
* Canvas c = new Canvas();
* c.setBitmap(b);
*/
Bitmap b = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
Canvas canvas2 = new Canvas(b);
Canvas能畫些什么
Canvas類提供了若干draw……的方法,從字面上我們就可以知道用這些方法我們可以繪制哪些東西。
填充
Canvas內(nèi)部維持了一個(gè)mutable Bitmap,所以我們可以用顏色來填充整個(gè)Bitmap。而填充的范圍受限于clip的范圍。
- drawRGB(int r, int g, int b):r-紅色要素(0255),g-綠色要素(0255),b-藍(lán)色要素(0~255)。
- drawARGB(int a, int r, int g, int b):a-透明度(0255),r-紅色要素(0255),g-綠色要素(0255),b-藍(lán)色要素(0255)。
- drawColor(int color):這里的color要為16進(jìn)制的顏色號(hào),例如:0xFF000000,共8位,兩位一組從左到右分別為ARGB,具體含義同上。若要使用“#FF000000”這樣的色號(hào),可以調(diào)用Color.parseColor(String colorString)方法來進(jìn)行轉(zhuǎn)換。
- drawColor(int color, PorterDuff.Mode mode):color同上,PorterDuff.Mode比較有意思,有很多種模式,每一種模式都會(huì)有特定的效果,感興趣的朋友可以自行了解一下。
- drawPaint(Paint paint):Canvas同樣可以用畫筆來填充Bitmap,當(dāng)然也受限于clip的范圍。
繪制圖形
- canvas.drawArc (扇形)
- canvas.drawCircle(圓)
- canvas.drawOval(橢圓)
- canvas.drawLine(線)
- canvas.drawPoint(點(diǎn))
- canvas.drawRect(矩形)
- canvas.drawRoundRect(圓角矩形)
- canvas.drawVertices(頂點(diǎn))
- cnavas.drawPath(路徑)
繪制圖片
- canvas.drawBitmap(位圖)
- canvas.drawPicture(圖片)
文本
- canvas.drawText
Canvas的變換
Canvas不僅僅可以draw一些圖形、圖片,其本身也提供了可操作的方法:rorate(旋轉(zhuǎn))、scale(壓縮)、translate(平移)、skew(扭曲)等。
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawRect(new Rect(0, 0, 200, 200), new Paint());
canvas.scale(0.5f, 0.5f);//縮放了
canvas.drawRect(new Rect(400, 400, 600, 600), new Paint());
canvas.translate(600, 600);//平移了
canvas.rotate(45);//旋轉(zhuǎn)了
canvas.drawRect(new Rect(0, 0, 200, 200), new Paint());
canvas.translate(200, 200);
canvas.skew(.5f, .5f);//扭曲了
canvas.drawRect(new Rect(0, 0, 200, 200), new Paint());
}

blog-20160309-1.png
Canvas的保存和回滾
為了配合Canvas本身的變換操作,Canvas提供了保持當(dāng)前狀態(tài)和回滾的方法。來個(gè)小例子。
我們準(zhǔn)備畫一個(gè)表盤,那么我們就有兩種實(shí)現(xiàn)的思路:
- 表盤上有60個(gè)刻度,每個(gè)刻度之間間隔6°,這是有規(guī)律的,那么我們就可以利用三角函數(shù)的知識(shí)來把刻度的兩個(gè)坐標(biāo)求出來,再利用drawLine畫到Canvas上??简?yàn)?zāi)氵壿嬎季S和數(shù)學(xué)功底的時(shí)候到了,不用仔細(xì)想就能知道這個(gè)方法有點(diǎn)麻煩。
- 如果不喜歡第一種方法,那么我們可以嘗試一下這一種。Canvas提供了旋轉(zhuǎn)操作的方法,也提供了保存和回復(fù)狀態(tài)的方法,那么我們就用這些搭配起來。首先我在(100,0)和(100,10)兩個(gè)坐標(biāo)之間畫一條豎線,很簡單,整點(diǎn)的刻度就出來了。之后先將Canvas的狀態(tài)保存起來,在(100,0)和(100,10)兩個(gè)坐標(biāo)之間畫一條豎線,回復(fù)Canvas的狀態(tài),一分鐘的刻度就出來了。以此類推,思路是不是很簡單。
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
for (int i = 0; i < 360; i = i + 6) {
canvas.save();
canvas.rotate(i, 100, 100);
canvas.drawLine(100, 0, 100, 10, new Paint());
canvas.restore();
}
}

blog-20160309-2.png