在上篇說道BitmapShader的使用
關(guān)于Shader.TileMode這個參數(shù)在說明一下
Shader.TileMode.CLAMP:畫布大于你畫的圖形時,圖形只顯示一個,剩下的畫布填充由圖形的四周顏色進行填充
效果:填充顏色根據(jù)邊緣填充
Shader.TileMode.REPEAT:畫布大于你畫的圖形時,圖形只顯示一個,剩下的畫布填充由圖形重復填充
Shader.TileMode.MIRROR:畫布大于你畫的圖形時,圖形只顯示一個,剩下的畫布填充由圖形鏡像填充
說明一下這里的 Shader.TileMode 可以設(shè)置不同
BitmapShader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.MIRROR,
Shader.TileMode.MIRROR);
shader有5個子類
LinearGradient使用
float x0, float y0起始xy
float x1, float y1結(jié)束xy
color0起始顏色
color1結(jié)束顏色
LinearGradient(float x0, float y0, float x1, float y1, int color0, int color1,TileMode tile)
LinearGradient(float x0, float y0, float x1, float y1, int colors[], float positions[],TileMode tile)
兩個構(gòu)造方法 一個顏色一個顏色數(shù)組
LinearGradient linearGradient = new LinearGradient(0,0,200,200, Color.BLUE,Color.RED,Shader.TileMode.CLAMP);
直接上三種效果
RadialGradient使用
centerX,centerY其實中心xy
radius半徑
RadialGradient(float centerX, float centerY, float radius, int centerColor, int edgeColor, Shader.TileMode tileMode)
RadialGradient(float centerX, float centerY, float radius, int[] colors, float[] stops, Shader.TileMode tileMode)
RadialGradient radialGradient = new RadialGradient(canvas.getWidth()/2f,canvas.getHeight()/2f,canvas.getWidth()/4f,Color.WHITE,Color.GRAY,Shader.TileMode.MIRROR);
SweepGradient使用
cx,cy 中心坐標
SweepGradient(float cx, float cy, int color0, int color1)
SweepGradient(float cx, float cy, int[] colors, float[] positions)
//顏色組
int[] colors = {Color.WHITE, Color.GRAY,Color.BLUE};
//按順時針3點鐘為0f,假如我們實現(xiàn)下半年部分180°為白色,左上90°為灰色,右上90°為藍色
float[] positions = {0.5f, 0.75f,1f};
//positions 如果null則顏色均勻分布
SweepGradient sweepGradient =
new SweepGradient(canvas.getWidth() / 2f, canvas.getHeight() / 2f, colors, positions );
這里我遇到一個問題一直困惑根據(jù)api了解
* @param positions May be NULL. The relative position of
* each corresponding color in the colors array, beginning
* with 0 and ending with 1.0. If the values are not
* monotonic, the drawing may produce unexpected results.
* If positions is NULL, then the colors are automatically
* spaced evenly.
*/
public SweepGradient(float cx, float cy,
int colors[], float positions[])
positions最大1.0,我在其他博客中看到如果設(shè)置不到小于1f,可顯示為帶有缺口的圖形,如果畫一個園設(shè)置小雨1.0f的數(shù)值 可顯示扇形
我試了,發(fā)現(xiàn)不行.float[] positions = {0.25f, 0.5f,0.75f};
ComposeShader
ComposeShader,顧名思義宰闰,就是混合Shader的意思屁桑,它可以將兩個Shader按照一定的Xfermode組合起來。
ComposeShader有兩個構(gòu)造函數(shù)泛释,如下所示:
ComposeShader(Shader shaderA, Shader shaderB, Xfermode mode)
ComposeShader(Shader shaderA, Shader shaderB, PorterDuff.Mode mode)
如果對Xfermode不熟悉的話胳嘲,強烈建議您先讀一下我的另一篇博文《Android中Canvas繪圖之PorterDuffXfermode使用及工作原理詳解》您没。
此處對Xfermode做一下簡單介紹故俐,Xfermode可以用于實現(xiàn)新繪制的像素與Canvas上對應位置已有的像素按照混合規(guī)則進行顏色混合。Xfermode有三個子類:AvoidXfermode, PixelXorXfermode和PorterDuffXfermode紊婉,其中前兩個類現(xiàn)在被Android廢棄了药版,現(xiàn)在主要用的是PorterDuffXfermode。PorterDuffXfermode的構(gòu)造函數(shù)需要指定PorterDuff.Mode的類型喻犁。所以槽片,上面的第二個構(gòu)造函數(shù)可以看做是第一個構(gòu)造函數(shù)的特例何缓。我們主要講解第二個,二者大同小異还栓。
我們知道碌廓,在使用Xfermode的時候,存在目標像素DST和源像素SRC之說剩盒。源像素指的是將要向Canvas上繪制的像素谷婆,目標像素指的是源像素在Canvas上對應位置已經(jīng)存在的像素。
構(gòu)造函數(shù)中的shaderA對應著目標像素辽聊,shaderB對應著源像素纪挎。
有一點需要說明,ComposeShader這個類不是必須的跟匆,也就是我們不用這個類也能創(chuàng)造對應的效果异袄,它類似于一個助手類,為我們實現(xiàn)某種效果提供了方便玛臂,下面舉例說明烤蜕。
我們有如下透明圖片:
上面的圖片是透明的,不過圖片中有個心形圖案是白色迹冤,不透明讽营。 我想讓漸變顏色只填充上圖中的?形區(qū)域,透明部分不填充泡徙,顏色從綠色漸變到藍色斑匪,漸變方向從左上角到右下角。我們不用ComposeShader即可實現(xiàn)上述效果锋勺,代碼如下所示:
int bitmapWidth = bitmap.getWidth();int bitmapHeight = bitmap.getHeight();//將繪制代碼放入到canvas.saveLayer()和canvas.restore()之間canvas.saveLayer(0, 0, bitmapWidth, bitmapHeight, null, Canvas.ALL_SAVE_FLAG); //創(chuàng)建BitmapShader,用以繪制?形 BitmapShader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); //將BitmapShader作為畫筆paint繪圖所使用的shader paint.setShader(bitmapShader); //用BitmapShader繪制矩形 canvas.drawRect(0, 0, bitmapWidth, bitmapHeight, paint); //將畫筆的Xfermode設(shè)置為PorterDuff.Mode.MULTIPLY模式 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY)); //創(chuàng)建LinearGradient狡蝶,用以產(chǎn)生從左上角到右下角的顏色漸變效果 LinearGradient linearGradient = new LinearGradient(0, 0, bitmapWidth, bitmapHeight, Color.GREEN, Color.BLUE, Shader.TileMode.CLAMP); //將創(chuàng)建LinearGradient作為畫筆paint繪圖所使用的shader paint.setShader(linearGradient); //用LinearGradient繪制矩形 canvas.drawRect(0, 0, bitmapWidth, bitmapHeight, paint); //最后將畫筆去除掉Xfermode paint.setXfermode(null);canvas.restore();
int bitmapWidth = bitmap.getWidth();
int bitmapHeight = bitmap.getHeight();
//將繪制代碼放入到canvas.saveLayer()和canvas.restore()之間
canvas.saveLayer(0, 0, bitmapWidth, bitmapHeight, null, Canvas.ALL_SAVE_FLAG);
//創(chuàng)建BitmapShader庶橱,用以繪制?形
BitmapShader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
//將BitmapShader作為畫筆paint繪圖所使用的shader
paint.setShader(bitmapShader);
//用BitmapShader繪制矩形
canvas.drawRect(0, 0, bitmapWidth, bitmapHeight, paint);
//將畫筆的Xfermode設(shè)置為PorterDuff.Mode.MULTIPLY模式
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));
//創(chuàng)建LinearGradient,用以產(chǎn)生從左上角到右下角的顏色漸變效果
LinearGradient linearGradient = new LinearGradient(0, 0, bitmapWidth, bitmapHeight, Color.GREEN, Color.BLUE, Shader.TileMode.CLAMP);
//將創(chuàng)建LinearGradient作為畫筆paint繪圖所使用的shader
paint.setShader(linearGradient);
//用LinearGradient繪制矩形
canvas.drawRect(0, 0, bitmapWidth, bitmapHeight, paint);
//最后將畫筆去除掉Xfermode
paint.setXfermode(null);
canvas.restore();
效果如下所示:
如果認真讀過博文《Android中Canvas繪圖之PorterDuffXfermode使用及工作原理詳解》的話贪惹,我相信大家應該能明白上圖出現(xiàn)的原因苏章。
此處我們還是一起分析一下代碼的執(zhí)行過程。
我們的圖片中間的?形區(qū)域是純白色奏瞬,該區(qū)域的像素顏色值A(chǔ)RGB分量是(255,255,255,255)枫绅。?形區(qū)域以外的區(qū)域是純透明的,該區(qū)域的像素顏色值A(chǔ)RGB分量是(0,0,0,0)硼端。
為了使用Xfermode并淋,我們將繪圖的代碼放到了canvas.saveLayer()和canvas.restore()之間,對此有疑問的同學可以參見我上述提到的博文珍昨。canvas.saveLayer()會創(chuàng)建一個新的繪圖圖層县耽,而且該圖層是全透明的句喷,我們后面的代碼都是繪制到這個圖層上,而不是直接繪制到Canvas上兔毙。
我們用上述Bitmap創(chuàng)建了一個BitmapShader唾琼,并將其綁定到畫筆Paint中。當我們用canvas.drawRect()繪制矩形時澎剥,就會用該BitmapShader填充锡溯,此時的效果應該是在新創(chuàng)建的layer上繪制了一個白色的心形。
然后我們創(chuàng)建了一個PorterDuffXfermode的實例哑姚,并通過paint.setXfermode()將其綁定到畫筆paint上祭饭。其中PorterDuffXfermode的mode類型為MULTIPLY。MULTIPLY的意思是將源像素的ARGB四個分量分別與目標像素對應的ARGB四個分量相乘蜻懦,將相乘的結(jié)果作為混合后的像素甜癞。此處進行相乘時,ARGB四個分量都已經(jīng)從[0, 255]的區(qū)間歸一化到[0.0, 1.0]的區(qū)間宛乃。
然后我們創(chuàng)建了一個LinearGradient悠咱,用以實現(xiàn)顏色線性漸變效果。顏色從左上角的綠色漸變到右下角的藍色征炼。然后我們通過paint.setShader()方法將其綁定到畫筆paint的shader上析既。
后面我們再次調(diào)用canvas.drawRect()繪制同樣大小的一個矩形。在繪制時谆奥,我們的畫筆已經(jīng)同時綁定了Xfermode和Shader眼坏。首先canvas會用LinearGradient繪制一個具有漸變色的矩形區(qū)域。然后根據(jù)畫筆設(shè)置的PorterDuff.Mode.MULTIPLY類型酸些,將那些由漸變色填充的矩形區(qū)域中的像素與我們在第3步中繪制的心形圖片中的像素顏色進行相乘混合宰译。漸變色填充的矩形區(qū)域中的像素是源像素,第3步中繪制的心形圖片中的像素是目標像素魄懂。目標像素中?形區(qū)域是純白色的沿侈,其像素顏色是(255,255,255,255),歸一化后的顏色是(1,1,1,1)市栗,對應位置的源像素中的ARGB顏色分量與其相乘缀拭,最終的顏色還是源像素的顏色,即心形區(qū)域被源像素著上了漸變色填帽。目標像素中?形區(qū)域以外的顏色是純透明的蛛淋,顏色是(0,0,0,0),對應位置的源像素中的ARGB顏色分量與其相乘篡腌,最終的顏色還是目標像素中的(0,0,0,0)褐荷,即心形區(qū)域以外沒有被著色,依舊呈現(xiàn)透明色嘹悼。
最后通過調(diào)用canvas.restore()方法將新創(chuàng)建的layer繪制到Canvas上去诚卸,這樣我們就看到最終的效果了葵第。
下面我們看看如和用ComposeShader實現(xiàn)上述效果,代碼如下所示:
int bitmapWidth = bitmap.getWidth();
int bitmapHeight = bitmap.getHeight();
//創(chuàng)建BitmapShader合溺,用以繪制?形
BitmapShader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
//創(chuàng)建LinearGradient卒密,用以產(chǎn)生從左上角到右下角的顏色漸變效果
LinearGradient linearGradient = new LinearGradient(0, 0, bitmapWidth, bitmapHeight, Color.GREEN, Color.BLUE, Shader.TileMode.CLAMP);
//bitmapShader對應目標像素,linearGradient對應源像素棠赛,像素顏色混合采用MULTIPLY模式
ComposeShader composeShader = new ComposeShader(bitmapShader, linearGradient, PorterDuff.Mode.MULTIPLY);
//將組合的composeShader作為畫筆paint繪圖所使用的shader
paint.setShader(composeShader);
//用composeShader繪制矩形區(qū)域
canvas.drawRect(0, 0, bitmapWidth, bitmapHeight, paint);
用ComposeShader實現(xiàn)的效果與上圖相同哮奇,我就不再貼圖了。我們可以看到睛约,使用ComposeShader之后鼎俘,實現(xiàn)相同的效果時,代碼量明顯減少了辩涝,而且我們也不需要將繪圖代碼放到canvas.saveLayer()和canvas.restore()之間了贸伐。
根據(jù)上面的示例,我們可以得出如下結(jié)論: 假設(shè)我們定義了兩個Shader的變量怔揩,shaderA和shaderB捉邢,并分別對這兩個Shader進行了實例化。 可以使用ComposeShader將二者組合使用商膊,基本代碼如下所示:
ComposeShader composeShader = new ComposeShader(shaderA, shaderB, porterDuffMode);
paint.setShader(composeShader);
canvas.drawXXX(..., paint);
上述代碼等價于下面的代碼片段:
canvas.saveLayer(left, top, right, bottom, null, Canvas.ALL_SAVE_FLAG);
paint.setShader(shaderA);
canvas.drawXXX(..., paint);
paint.setXfermode(new PorterDuffXfermode(mode));
paint.setShader(shaderB);
canvas.drawXXX(..., paint);
paint.setXfermode(null);
canvas.restore();
此處所說的以上兩個代碼片段等價的前提是伏伐,兩個代碼片段中的canvas.drawXXX(…, paint)方法中調(diào)用的drawXXX方法相同,并且里面?zhèn)魅氲膮?shù)都相同晕拆,例如我們之前兩段心形代碼示例中都調(diào)用drawRect()方法且繪制的矩形的位置及尺寸都相同藐翎。
ComposeShader內(nèi)容來自http://blog.csdn.net/iispring/article/details/50500106