android shader使用

在上篇說道BitmapShader的使用
關(guān)于Shader.TileMode這個參數(shù)在說明一下
Shader.TileMode.CLAMP:畫布大于你畫的圖形時,圖形只顯示一個,剩下的畫布填充由圖形的四周顏色進行填充
效果:填充顏色根據(jù)邊緣填充


Paste_Image.png

Shader.TileMode.REPEAT:畫布大于你畫的圖形時,圖形只顯示一個,剩下的畫布填充由圖形重復填充

Paste_Image.png

Shader.TileMode.MIRROR:畫布大于你畫的圖形時,圖形只顯示一個,剩下的畫布填充由圖形鏡像填充

Paste_Image.png

說明一下這里的 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);

直接上三種效果

Paste_Image.png

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);
Paste_Image.png

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市实幕,隨后出現(xiàn)的幾起案子吝镣,更是在濱河造成了極大的恐慌,老刑警劉巖昆庇,帶你破解...
    沈念sama閱讀 221,695評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件末贾,死亡現(xiàn)場離奇詭異,居然都是意外死亡凰锡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評論 3 399
  • 文/潘曉璐 我一進店門圈暗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來掂为,“玉大人,你說我怎么就攤上這事员串∮禄” “怎么了?”我有些...
    開封第一講書人閱讀 168,130評論 0 360
  • 文/不壞的土叔 我叫張陵寸齐,是天一觀的道長欲诺。 經(jīng)常有香客問我抄谐,道長,這世上最難降的妖魔是什么扰法? 我笑而不...
    開封第一講書人閱讀 59,648評論 1 297
  • 正文 為了忘掉前任蛹含,我火速辦了婚禮,結(jié)果婚禮上塞颁,老公的妹妹穿的比我還像新娘浦箱。我一直安慰自己,他們只是感情好祠锣,可當我...
    茶點故事閱讀 68,655評論 6 397
  • 文/花漫 我一把揭開白布酷窥。 她就那樣靜靜地躺著,像睡著了一般伴网。 火紅的嫁衣襯著肌膚如雪蓬推。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,268評論 1 309
  • 那天澡腾,我揣著相機與錄音沸伏,去河邊找鬼。 笑死蛋铆,一個胖子當著我的面吹牛馋评,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播刺啦,決...
    沈念sama閱讀 40,835評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼留特,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了玛瘸?” 一聲冷哼從身側(cè)響起蜕青,我...
    開封第一講書人閱讀 39,740評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎糊渊,沒想到半個月后右核,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,286評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡渺绒,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,375評論 3 340
  • 正文 我和宋清朗相戀三年贺喝,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片宗兼。...
    茶點故事閱讀 40,505評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡躏鱼,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出殷绍,到底是詐尸還是另有隱情染苛,我是刑警寧澤,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布主到,位于F島的核電站茶行,受9級特大地震影響躯概,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜畔师,卻給世界環(huán)境...
    茶點故事閱讀 41,873評論 3 333
  • 文/蒙蒙 一娶靡、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧茉唉,春花似錦固蛾、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至懂傀,卻和暖如春趾诗,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蹬蚁。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評論 1 272
  • 我被黑心中介騙來泰國打工恃泪, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人犀斋。 一個月前我還...
    沈念sama閱讀 48,921評論 3 376
  • 正文 我出身青樓贝乎,卻偏偏與公主長得像,于是被迫代替她去往敵國和親叽粹。 傳聞我的和親對象是個殘疾皇子览效,可洞房花燭夜當晚...
    茶點故事閱讀 45,515評論 2 359

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