Canvas(畫布),繪制的載體沿彭,可以通過Paint(畫筆)在上面繪制所有你想繪制的圖案。
1尖滚、Canvas繪制API
其包含一系列drawXXX方法:
1喉刘、繪制顏色
public void drawColor(int color)
public void drawARGB(int a, int r, int g, int b)
public void drawRGB(int r, int g, int b)
2瞧柔、繪制形狀
繪制點(diǎn)
void drawPoint(float x, float y, Paint paint)
void drawPoints(float[] pts, Paint paint)
void drawPoints(float[] pts, int offset, int count, Paint paint)
繪制線段
void drawLine(float startX, float startY, float stopX, float stopY, Paint paint)
void drawLines(float[] pts, int offset, int count, Paint paint)
void drawLines(float[] pts, Paint paint)
繪制矩形
void drawRect(RectF rect, Paint paint)
void drawRect(Rect r, Paint paint)
void drawRect(float left, float top, float right, float bottom, Paint paint)
繪制圓角矩形,與shape標(biāo)簽不同的是睦裳,它不能單獨(dú)設(shè)置4個(gè)圓角
void drawRoundRect(RectF rect, float rx, float ry, Paint paint)
void drawRoundRect(float left, float top, float right, float bottom, float rx, float ry, Paint paint)
繪制雙框圓角矩形
void drawDoubleRoundRect( RectF outer, float outerRx, float outerRy, RectF inner, float innerRx, float innerRy, Paint paint)
/**
* 這個(gè)方法通過內(nèi)外邊框來完成繪制造锅,且內(nèi)外邊框的四個(gè)角的圓角半徑都可控
* @param outer 外邊框的范圍
* @param inner 內(nèi)邊框的范圍
* @param innerRadii、outerRadii
* 這兩個(gè)float數(shù)組分別保存了內(nèi)外邊框的四個(gè)角的圓角半徑
* 每個(gè)數(shù)組需要傳入8個(gè)float推沸,每?jī)蓚€(gè)為一組 rx备绽,ry即圓角半徑在x,y方向的值
* @param paint 這里我傳入的paint里面保存著bitmapShader
* 此外需要注意設(shè)置Style:
* FILL將會(huì)繪制到兩個(gè)矩形(RectF)中間的內(nèi)容
* STROKE,就是會(huì)把兩個(gè)邊框給繪制出來鬓催。
*/
void drawDoubleRoundRect(RectF outer, float[] outerRadii, RectF inner, float[] innerRadii, Paint paint)
繪制圓
void drawCircle(float cx, float cy, float radius, Paint paint)
繪制橢圓
void drawOval(RectF oval, Paint paint)
void drawOval(float left, float top, float right, float bottom, Paint paint)
繪制弧
void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint)
void drawArc(float left, float top, float right, float bottom, float startAngle, float sweepAngle, boolean useCenter, Paint paint)
繪制路徑
void drawPath(Path path, Paint paint)
3肺素、繪制圖像
void drawBitmap(Bitmap bitmap, float left, float top, Paint paint)
void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint)
void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint)
void drawPicture(Picture picture)
void drawPicture(Picture picture, RectF dst)
android.graphics.Picture
相對(duì)于Drawable和Bitmap來說,更加小巧宇驾,它并不存儲(chǔ)實(shí)際的像素倍靡,僅僅記錄了每個(gè)繪制的過程。使用介紹
4课舍、繪制文字
- 繪制常規(guī)文字
void drawText(char[] text, int index, int count, float x, float y, Paint paint)`
void drawText(String text, float x, float y, Paint paint)
void drawText(String text, int start, int end, float x, float y, Paint paint)
void drawText(CharSequence text, int start, int end, float x, float y, Paint paint)
注意:這里x和y坐標(biāo)分別表示文字起始位置和文字基線位置坐標(biāo)塌西。
- 沿路徑繪制文字
void drawTextOnPath(char[] text, int index, int count, Path path, float hOffset, float vOffset, Paint paint)
void drawTextOnPath(String text, @NonNull Path path, float hOffset, float vOffset, Paint paint)
float hOffset:與路徑起始點(diǎn)的水平偏移量
float vOffset:與路徑起始點(diǎn)的垂直偏移量
- drawTextRun
對(duì)漢字沒用,可以不用了解
void drawTextRun(char[] text, int index, int count, int contextIndex, int contextCount, float x, float y, boolean isRtl, Paint paint)
void drawTextRun(CharSequence text, int start, int end, int contextStart, int contextEnd, float x, float y, boolean isRtl, Paint paint)
void drawTextRun(MeasuredText text, int start, int end, int contextStart, int contextEnd, float x, float y, boolean isRtl, Paint paint)
- 其余:
public void drawPaint(Paint paint)
繪制3D圖形利器
void drawVertices(@NonNull VertexMode mode, int vertexCount, @NonNull float[] verts,
int vertOffset, @Nullable float[] texs, int texOffset, @Nullable int[] colors,
int colorOffset, @Nullable short[] indices, int indexOffset, int indexCount,
@NonNull Paint paint)
2筝尾、Canvas變換操作
1捡需、每次調(diào)用drawXXX系列函數(shù)來繪圖時(shí),都會(huì)產(chǎn)生一個(gè)全新的Canvas透明圖層筹淫。
2站辉、如果在調(diào)用drawXXX系列函數(shù)前,調(diào)用平移损姜、旋轉(zhuǎn)等函數(shù)對(duì)Canvas進(jìn)行了操作饰剥,那么這個(gè)操作是不可逆的。每次產(chǎn)生的畫布的狀態(tài)都是執(zhí)行這些操作后的狀態(tài)摧阅。
3汰蓉、在Canvas圖層與屏幕合成時(shí),超出屏幕范圍的圖像是不會(huì)顯示出來的棒卷。
Canvas變換只會(huì)影響后續(xù)繪制內(nèi)容顾孽。
1、平移操作
void translate(float dx, float dy)
2比规、縮放操作
void sacle(float sx, float sy)
相當(dāng)于先translate(dx, dy)岩齿,再sacle(sx, sy),再反向translate(-dx, -dy)
void sacle(float sx, float sy, float dx, float dy)
3、旋轉(zhuǎn)操作
void rotate(float degress)
void rotate(float degress, float px, float py)
4苞俘、傾斜操作
void skew(float sx, float sy)
5盹沈、Matrix,通過矩陣等操作Canvas
void setMatrix(Matrix matrix)
3、Canvas裁剪
切割操作乞封,只能繪制圖像到指定區(qū)域內(nèi)
void clipXXX(...)
反切割操作做裙,只能繪制圖像到指定區(qū)域外
void clipOutXXX(...)
注意:clip系列函數(shù)需要禁用硬件加速功能
setLayerType (LAYER_TYPE_SOFTWARE,null) ;
4、狀態(tài)恢復(fù)與保存
當(dāng)Canvas經(jīng)過變換操作或裁剪操作后肃晚,后續(xù)操作都是基于變換后的Canvas锚贱,都將受到影響。所以Canvas提供save
关串、restore
和restoreToCount
方法來保存和恢復(fù)狀態(tài)拧廊。
1、save
int save()
會(huì)保存當(dāng)前Canvas的Matrix
和Clip
等信息到Canvas的私有棧中晋修。
返回當(dāng)前棧的位置吧碾,可作為Canvas.restoreToCount()
的入?yún)ⅲ糜诳焖倩謴?fù)到當(dāng)前狀態(tài)墓卦。2倦春、restore
void restore()
Canvas的私有棧中恢復(fù)Matrix
和Clip
等信息。3落剪、restoreToCount
void restoreToCount(int saveCount)
與restore()
類似睁本,但restore()
只能依次從私有棧中彈出,而restoreToCount()
忠怖,可以彈出到私有棧中特定的位置呢堰。
示例代碼如下:
canvas.drawRect(100, 100, 300, 300, paint);
int count = canvas.save();
canvas.rotate(45, 200, 200);
paint.setColor(Color.GRAY);
canvas.drawRect(100, 100, 300, 300, paint);
canvas.restoreToCount(count);
canvas.drawLine(200, 100, 200, 300, paint);
5、離屏渲染
離屏渲染凡泣,意思是把內(nèi)容繪制到單獨(dú)的緩沖畫布中暮胧,從而保證繪制的內(nèi)容不受舊畫布的影響。一般配合Xfermode
使用问麸,同時(shí)需要禁止硬件加速。
Android通過了saveLayer
钞翔、saveLayerAlpha
兩個(gè)方法來實(shí)現(xiàn)離屏渲染严卖。它們能夠?yàn)镃anvas創(chuàng)建一個(gè)緩沖畫布,后續(xù)對(duì)該Canvas的操作都將基于最新的畫布上來完成布轿。
saveLayer
int saveLayer(RectF bounds, Paint paint)
int saveLayer(float left, float top, float right, float bottom, Paint paint)
創(chuàng)建緩沖畫布哮笆,并保存畫筆對(duì)象,并在離屏渲染結(jié)束后汰扭,畫布restore()時(shí)稠肘,將緩沖畫布用該畫筆與舊畫布進(jìn)行混合。saveLayerAlpha
int saveLayerAlpha(RectF bounds, int alpha)
int saveLayerAlpha(float left, float top, float right, float bottom, int alpha)
創(chuàng)建緩沖畫布萝毛,在離屏渲染結(jié)束后项阴,畫布restore()時(shí),將緩沖畫布用alpha與舊畫布進(jìn)行混合笆包。
一般流程是:先繪制目標(biāo)圖
(dst)环揽,然后設(shè)置Xfermode
略荡,再繪制原圖
(src),最后清除Xfermode
歉胶。
代碼如下:
//禁止使用硬件加速
setLayerType(View.LAYER_TYPE_HARDWARE, null);
//離屏繪制
int layerId = canvas.saveLayer(0, 0, getWidth(), getHeight(), paint, Canvas.ALL_SAVE_FLAG);
//繪制目標(biāo)圖
canvas.drawBitmap(createDstBitmap(), 0, 0, paint);
//設(shè)置混合模式
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
//繪制原圖
canvas.drawBitmap(createSrcBitmap(), 0, 0, paint);
//清除混合模式
paint.setXfermode(null);
canvas.restoreToCount(layerId);
更多有關(guān)Xfermode和硬件加速的知識(shí)汛兜,請(qǐng)參考:Android繪制知識(shí)總結(jié)(Xfermode和硬件加速)