四佛析、Android繪制知識(shí)總結(jié)(畫布篇)

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)的垂直偏移量


image.png
  • 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关串、restorerestoreToCount方法來保存和恢復(fù)狀態(tài)拧廊。

  • 1、save
    int save()
    會(huì)保存當(dāng)前Canvas的MatrixClip等信息到Canvas的私有棧中晋修。
    返回當(dāng)前棧的位置吧碾,可作為Canvas.restoreToCount()的入?yún)ⅲ糜诳焖倩謴?fù)到當(dāng)前狀態(tài)墓卦。

  • 2倦春、restore
    void restore()
    Canvas的私有棧中恢復(fù)MatrixClip等信息。

  • 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和硬件加速)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市通今,隨后出現(xiàn)的幾起案子粥谬,更是在濱河造成了極大的恐慌,老刑警劉巖辫塌,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件漏策,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡璃氢,警方通過查閱死者的電腦和手機(jī)哟玷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來一也,“玉大人巢寡,你說我怎么就攤上這事∫叮” “怎么了抑月?”我有些...
    開封第一講書人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)舆蝴。 經(jīng)常有香客問我谦絮,道長(zhǎng),這世上最難降的妖魔是什么洁仗? 我笑而不...
    開封第一講書人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任层皱,我火速辦了婚禮,結(jié)果婚禮上赠潦,老公的妹妹穿的比我還像新娘叫胖。我一直安慰自己,他們只是感情好她奥,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開白布瓮增。 她就那樣靜靜地躺著,像睡著了一般哩俭。 火紅的嫁衣襯著肌膚如雪绷跑。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,036評(píng)論 1 285
  • 那天凡资,我揣著相機(jī)與錄音砸捏,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛带膜,可吹牛的內(nèi)容都是我干的吩谦。 我是一名探鬼主播,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼膝藕,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼式廷!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起芭挽,我...
    開封第一講書人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤滑废,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后袜爪,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蠕趁,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年辛馆,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了俺陋。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡昙篙,死狀恐怖腊状,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情苔可,我是刑警寧澤缴挖,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站焚辅,受9級(jí)特大地震影響映屋,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜同蜻,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一棚点、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧湾蔓,春花似錦瘫析、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽么库。三九已至傻丝,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間诉儒,已是汗流浹背葡缰。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人泛释。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓滤愕,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親怜校。 傳聞我的和親對(duì)象是個(gè)殘疾皇子间影,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容