概述
在Android中,我們經(jīng)常會(huì)需要去繪制一些自己需要的控件,所以繼承自View的自定義View就產(chǎn)生了。這篇文章主要介紹在View中的重要類,Canvas類的一些基本使用。
Canvas繪制背景
Canvas繪制背景主要有幾個(gè)方法
/**
* 使用srcover-porterduff模式,用指定的顏色填充整個(gè)畫布的位圖(限于當(dāng)前剪輯)
*
* @param color the color to draw onto the canvas
*/
public void drawColor(@ColorInt int color) {
super.drawColor(color);
}
/**
* 使用srcover-porterduff模式,用指定的顏色填充整個(gè)畫布的位圖(限于當(dāng)前剪輯)
*
* @param color the {@code ColorLong} to draw onto the canvas. See the {@link Color}
* class for details about {@code ColorLong}s.
* @throws IllegalArgumentException if the color space encoded in the {@code ColorLong}
* is invalid or unknown.
*/
public void drawColor(@ColorLong long color){
super.drawColor(color, BlendMode.SRC_OVER);
}
/**
* 使用指定的顏色和porter duff xfermode填充整個(gè)畫布的位圖(僅限于當(dāng)前剪輯)。
*
* @param color the color to draw onto the canvas
* @param mode the porter-duff mode to apply to the color
*/
public void drawColor(@ColorInt int color, @NonNull PorterDuff.Mode mode) {
super.drawColor(color, mode);
}
/**
* 使用指定的顏色和blendmode填充整個(gè)畫布的位圖(僅限于當(dāng)前剪輯)。
*
* @param color the color to draw onto the canvas
* @param mode the blendmode to apply to the color
*/
public void drawColor(@ColorInt int color, @NonNull BlendMode mode) {
super.drawColor(color, mode);
}
/**
* 使用指定的顏色和blendmode填充整個(gè)畫布的位圖(僅限于當(dāng)前剪輯)。
*
* @param color the {@code ColorLong} to draw onto the canvas. See the {@link Color}
* class for details about {@code ColorLong}s.
* @param mode the blendmode to apply to the color
* @throws IllegalArgumentException if the color space encoded in the {@code ColorLong}
* is invalid or unknown.
*/
public void drawColor(@ColorLong long color, @NonNull BlendMode mode) {
super.drawColor(color, mode);
}
畫布的平移
一般采用下面的方法進(jìn)行canvas的平移
/**
* Preconcat the current matrix with the specified translation
*
* @param dx The distance to translate in X
* @param dy The distance to translate in Y
*/
public void translate(float dx, float dy) {
if (dx == 0.0f && dy == 0.0f) return;
nTranslate(mNativeCanvasWrapper, dx, dy);
}
這個(gè)方法可以將canvas的參考坐標(biāo)平移,并不是平移之前已經(jīng)繪制的內(nèi)容,看下面一個(gè)例子大家就明白了,代碼步驟是這樣
- 繪制一個(gè)矩形
- 平移畫布
- 再繪制一個(gè)矩形
代碼如下
@Override
protected void onDraw(Canvas canvas){
super.onDraw(canvas);
Log.d(TAG,"onDraw");
// 設(shè)置畫筆的寬度
paint.setStrokeWidth(5f);
// 設(shè)置畫筆的顏色
paint.setColor(Color.RED);
// 設(shè)置畫筆的Style
paint.setStyle(Paint.Style.STROKE);
// 繪制一個(gè)矩形
canvas.drawRect(rectF,paint);
// 平移畫布
canvas.translate(100,100);
// 繪制矩形
rectF = new RectF(width/2-300,height/2-150,width/2+300,height/2+150);
canvas.drawRect(rectF,paint);
}
運(yùn)行結(jié)果是這樣的

明白了吧,canvas只是你繪制時(shí)的一個(gè)圖層而已,當(dāng)你平移之后,并不影響之前已經(jīng)繪制過的內(nèi)容,所以在使用平移畫布時(shí)請記得這點(diǎn)。
Canvas的裁剪,狀態(tài)的保存和恢復(fù)
1.畫布的裁剪
在學(xué)習(xí)裁剪之前,需要先搞清楚一個(gè)概念,這里畫布的裁剪的意義與我們所理解的裁剪紙張的意義是不一樣的,這里的裁剪好比你原本可以在一張完整的紙上進(jìn)行繪制,裁剪后,就好像你的紙張被一張透明的玻璃蓋住,中間你裁剪的部分就是空心的,可以往下面的紙張上繼續(xù)畫東西,其余部分則無法繪制,你只能看到之前繪制的內(nèi)容,你如果裁剪出是一個(gè)圓形,那么你就是在這個(gè)圓中繪制你的內(nèi)容,但是這并不影響顯示你之前已經(jīng)在紙上繪制出來的內(nèi)容.
非常重要的點(diǎn)
裁剪是不可逆的 ! ! !
裁剪是不可逆的 ! ! !
裁剪是不可逆的 ! ! !
所以我們在使用裁剪時(shí)如果需要恢復(fù),是必須要結(jié)合畫布的保存和恢復(fù)一起使用的.裁剪使用的方法主要有以下幾種
還要注意一點(diǎn) 使用裁剪時(shí)需要關(guān)閉硬件加速
setLayerType(LAYER_TYPE_SOFTWARE,null);
- clipOutRect()系列的函數(shù),主要用來裁剪出一個(gè)矩形之外的部分
- clipRect()系列的函數(shù),主要用來裁剪出一個(gè)矩形
- clipOutPath()系列的函數(shù),主要用來裁剪出一個(gè)路徑外的部分,一般是封閉的圖形
- clipPath()系列的函數(shù),主要用來裁剪出一個(gè)路徑內(nèi)的部分,一般為封閉圖形
2.畫布的狀態(tài)保存與恢復(fù)
- 保存
int save() - 恢復(fù)
void restore() - 恢復(fù)到指定狀態(tài)
void restoreToCount(int saveCount)
這里我們結(jié)合一個(gè)具體的例子來進(jìn)行說明,例子的繪制步驟是這樣的 - 1.給Canvas一個(gè)綠色背景
- 2.保存Canvas狀態(tài)
- 3.在中心裁剪出一個(gè)矩形
- 4.在裁剪后的Canvas中加入灰色背景色
- 5.恢復(fù)畫布狀態(tài)
- 6.在恢復(fù)后的Canvas上畫一個(gè)裁剪范圍之外的藍(lán)色的矩形框
好了我們開始寫代碼,代碼也很簡單
@Override
protected void onDraw(Canvas canvas){
super.onDraw(canvas);
Log.d(TAG,"onDraw");
// 設(shè)置畫筆的寬度
paint.setStrokeWidth(10f);
// 設(shè)置畫筆的顏色
paint.setColor(Color.BLUE);
// 設(shè)置畫筆的Style
paint.setStyle(Paint.Style.STROKE);
// 繪制背景色綠色
canvas.drawColor(Color.GREEN);
// 保存此時(shí)畫布狀態(tài)
int saveCount = canvas.save();
// 在畫布中間裁剪出一個(gè)矩形
RectF rectF = new RectF(width/2-300,height/2-150,width/2+300,height/2+150);
canvas.clipRect(rectF);
// 繪制灰色背景方便觀察
canvas.drawColor(Color.GRAY);
// 恢復(fù)畫布狀態(tài),即裁剪之前
canvas.restoreToCount(saveCount);
// canvas.restore(); 恢復(fù)至上一個(gè)保存狀態(tài),這里和canvas.restoreToCount(saveCount)效果是一致的,擇一調(diào)用即可。
// 恢復(fù)后繪制一個(gè)矩形
RectF rectB = new RectF(20,20,width-20,height-20);
canvas.drawRect(rectB,paint);
}
運(yùn)行結(jié)果如下

為了驗(yàn)證我們的Canvas恢復(fù)是有效的,我們把恢復(fù)的代碼注釋掉,像這樣
// 恢復(fù)畫布狀態(tài),即裁剪之前
// canvas.restoreToCount(saveCount);
運(yùn)行后變成了這樣

我們最后繪制的藍(lán)色矩形框沒了,所以裁剪后在裁剪范圍外繪制的內(nèi)容是無效的,但是裁剪前繪制的內(nèi)容是不影響顯示的,所以這樣可以理解裁剪時(shí)類似透明玻璃層的概念了吧
總結(jié)
Canvas的背景繪制,平移,狀態(tài)保存和恢復(fù)就整理到這里了,下篇總結(jié)一下視圖動(dòng)畫~