三:自定義view,繪制圓形圖片

1容客、BitmapShader

可以通過為paint指定一個漸變(BitmapShader郊尝,Paint.setShader(shader))二跋,以圖片填充BitmapShader,就可以得到如下圓形圖片流昏。

使用BitmapShader繪制圓形
1扎即、漸變模式

BitmapShader,位圖漸變况凉,是將圖片作為背景谚鄙,繪制到指定的位圖中,如果圖片比為圖小刁绒,則以以下模式進(jìn)行填充:

  • TileMode.CLAMP :不平鋪闷营,即AABB型
  • TileMode.REPEAT :平鋪,即ABABA型
  • TileMode.MIRROR:鏡像平鋪知市,即ABBA型

效果如下

位圖漸變下的CLAMP
位圖漸變下的REPEAT
位圖漸變下的MIRROR
線性漸變下的CLAMP 傻盟、MIRROR、REPEAT
2初狰、Matrix

可以使用 shader.setLocalMatrix(localM)莫杈,使Matrix 和漸變結(jié)合,實現(xiàn) 位移奢入、旋轉(zhuǎn)筝闹、縮放媳叨、拉斜的漸變效果,如下可以縮放被填充的圖片关顷,移動其中心點(diǎn)到位圖的中心點(diǎn)糊秆。

主要代碼如下


        BitmapShader shader=new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);

         //計算縮放比例,縮放被填充的圖片议双,移動其中心點(diǎn)到位圖的中心點(diǎn)
        Matrix localM=new Matrix();
        int bitmapWidth=bitmap.getWidth();
        int bitmapHeight=bitmap.getHeight();

        float scaleX=width/(bitmapWidth*1.0f);
        float scaleY=height/(bitmapHeight*1.0f);
        float scale=Math.max(scaleX,scaleY);
        localM.setScale(scale,scale);

        if(scaleX<scaleY){
            localM.postTranslate((bitmapWidth*scaleY-bitmapWidth*scaleX)/2,0);
        }else {
            localM.postTranslate(0,(bitmapHeight*scaleX-bitmapHeight*scaleY)/2);
        }
        
        //縮放痘番、平移漸變
        shader.setLocalMatrix(localM);
        //為paint指定一個漸變
        paint.setShader(shader);

        canvas.drawCircle(centerX,centerY,radius,paint);

當(dāng)然除了圓形,也可以繪制其他任意形狀

        path.moveTo(0,height/3);
        path.lineTo(width,height/3);
        path.lineTo(width/4,height);
        path.lineTo(width/2,0);
        path.lineTo(3*width/4,height);
        path.close();
        canvas.drawPath(path,paint);
使用BitmapShader繪制

2平痰、xfermode

可以先在畫布上畫圖片汞舱,在將xfermode設(shè)為DST_IN,在畫圓宗雇,如下:

xfermode昂芜,DST_IN

代碼如下

        xfermode=new PorterDuffXfermode(PorterDuff.Mode.DST_IN);

        ...

        int width=getMeasuredWidth();
        int height=getMeasuredHeight();
        int radius=Math.min(width/2,height/2);
        int centerX=width/2;
        int centerY=height/2;

        desbitmap=Bitmap.createScaledBitmap(bitmap,width,height,true);

        circleBitmap=Bitmap.createBitmap(width,height, Bitmap.Config.ARGB_8888);
        Canvas canvas=new Canvas(circleBitmap);
        canvas.drawCircle(centerX,centerY,radius,paint);


        int layer=canvas.saveLayer(0,0,getMeasuredWidth(),getMeasuredHeight(),null,Canvas.ALL_SAVE_FLAG);
        paint.setXfermode(xfermode);
        canvas.drawBitmap(desbitmap,0,0,null);
        canvas.drawBitmap(circleBitmap,0,0,paint);
        paint.setXfermode(null);
        canvas.restoreToCount(layer);


當(dāng)然,也可以是其他形狀

panda

1赔蒲、 關(guān)于xfermode

PorterDuffXfermode泌神,可以將所繪制的圖形的像素與Canvas中對應(yīng)位置的像素按照一定規(guī)則進(jìn)行混合,形成新的像素值舞虱。當(dāng)使用PorterDuffXfermode時欢际,需要將將其作為參數(shù)傳給Paint.setXfermode(Xfermode xfermode)方法,這樣在用該畫筆paint進(jìn)行繪圖時矾兜,Android就會使用傳入的PorterDuffXfermode损趋,如果不想再使用Xfermode,那么可以執(zhí)行Paint.setXfermode(null)焕刮。

一般我們在調(diào)用canvas.drawXXX()方法時都會傳入一個畫筆Paint對象舶沿,Android在繪圖時會先檢查該畫筆Paint對象有沒有設(shè)置Xfermode,如果沒有設(shè)置Xfermode配并,那么直接將繪制的圖形覆蓋Canvas對應(yīng)位置原有的像素括荡;如果設(shè)置了Xfermode,那么會按照Xfermode具體的規(guī)則來更新Canvas中對應(yīng)位置的像素顏色溉旋。就本例來說畸冲,在執(zhí)行canvas.drawCirlce()方法時,畫筆Paint沒有設(shè)置Xfermode對象观腊,所以繪制的黃色圓形直接覆蓋了Canvas上的像素邑闲。當(dāng)我們調(diào)用canvas.drawRect()繪制矩形時,畫筆Paint已經(jīng)設(shè)置Xfermode的值為PorterDuff.Mode.CLEAR梧油,此時Android首先是在內(nèi)存中繪制了這么一個矩形苫耸,所繪制的圖形中的像素稱作源像素(source,簡稱src)儡陨,所繪制的矩形在Canvas中對應(yīng)位置的矩形內(nèi)的像素稱作目標(biāo)像素(destination褪子,簡稱dst)量淌。源像素的ARGB四個分量會和Canvas上同一位置處的目標(biāo)像素的ARGB四個分量按照Xfermode定義的規(guī)則進(jìn)行計算,形成最終的ARGB值嫌褪,然后用該最終的ARGB值更新目標(biāo)像素的ARGB值呀枢。
本例中的Xfermode是PorterDuff.Mode.CLEAR,該規(guī)則比較簡單粗暴笼痛,直接要求目標(biāo)像素的ARGB四個分量全置為0裙秋,即(0,0缨伊,0摘刑,0),即透明色刻坊,所以我們通過canvas.drawRect()在Canvas上繪制了一個透明的矩形泣侮,由于Activity本身屏幕的背景時白色的,所以此處就顯示了一個白色的矩形紧唱。


PorterDuff.Mode.CLEAR,沒有使用layer

PorterDuffXfermode支持以下十幾種像素顏色的混合模式隶校,分別為:CLEAR漏益、SRC、DST深胳、SRC_OVER绰疤、DST_OVER、SRC_IN舞终、DST_IN轻庆、SRC_OUT、DST_OUT敛劝、SRC_ATOP余爆、DST_ATOP、XOR夸盟、DARKEN蛾方、LIGHTEN、MULTIPLY上陕、SCREEN桩砰。

我們知道一個像素的顏色由四個分量組成,即ARGB释簿,第一個分量A表示的是Alpha值亚隅,后面三個分量RGB表示了顏色。我們用S代表源像素庶溶,源像素的顏色值可表示為[Sa, Sc]煮纵,Sa中的a是alpha的縮寫懂鸵,Sa表示源像素的Alpha值,Sc中的c是顏色color的縮寫醉途,Sc表示源像素的RGB矾瑰。我們用D代表目標(biāo)像素,目標(biāo)像素的顏色值可表示為[Da, Dc]隘擎,Da表示目標(biāo)像素的Alpha值殴穴,Dc表示目標(biāo)像素的RGB。

源像素與目標(biāo)像素在不同混合模式下計算顏色的規(guī)則如下所示:

SRC:[Sa, Sc]货葬,顯示上層位圖
1采幌、SRC

2、SRC
DST:[Da, Dc]震桶,只顯示下層位圖
1休傍、DST
SRC_OVER:[Sa + (1 - Sa)Da, Rc = Sc + (1 - Sa)Dc],上下層都顯示蹲姐,運(yùn)算后上層顯示在上面
1磨取、SRC_OVER
DST_OVER:[Sa + (1 - Sa)Da, Rc = Dc + (1 - Da)Sc],上下層都顯示柴墩,運(yùn)算后下層顯示在上面
1忙厌、DST
SRC_IN:[Sa * Da, Sc ** Da],取兩層交集部分江咳,內(nèi)容取決于上層
1逢净、SRC
DST_IN:[Sa * Da, Sa ** Dc],取兩層交集部分歼指,內(nèi)容取決于下層
1爹土、DST_IN

2、DST_IN
SRC_OUT:[Sa * (1 - Da), Sc (1 - Da)]踩身,取上層非交集部分
SRC_OUT胀茵,這里,Da * (1 - Sa)惰赋,透明度始終是0
DST_OUT:[Da * (1 - Sa), Dc (1 - Sa)]宰掉,取下層非交集部分
DST_OUT
SRC_ATOP:[Da, Sc * Da + (1 - Sa) Dc]
SRC_ATOP
DST_ATOP:[Sa, Sa * Dc + Sc (1 - Da)]
DST_ATOP
XOR:[Sa + Da - 2 Sa * Da, Sc (1 - Da) + (1 - Sa) Dc]
XOR

。赁濒。轨奄。

xfermode

注:xfermode,計算的是重疊部分的最終像素
1拒炎、des(圖片)挪拟、src(空心圓)和最終位圖大小相等,src是空心圓
2击你、des(黃圓)玉组、src(藍(lán)谎柄,矩形)和最終位圖大小相等

參考:Android中Canvas繪圖之PorterDuffXfermode使用及工作原理詳解

2、關(guān)于 Canvas c=new Canvas(mybitmap):

        ...
        Bitmap mybitmap=BitmapFactory.decodeResource(context.getResources(),R.drawable.test3);
        boolean isMutable=mybitmap.isMutable();
        Canvas c=new Canvas(mybitmap);
        ...

如果這樣設(shè)置惯雳,會報錯:

 Immutable bitmap passed to Canvas constructor

就是說如果bitmap不可改變的情況下朝巫,canvas是不允許進(jìn)行繪制的, 當(dāng)你用BitmapFactory.decodeResource,返回的bitmap是默認(rèn)狀態(tài)下的mIsMutable=false石景。而使用Bitmap.createBitmap()返回的是 true劈猿。

        ...
        Bitmap b=BitmapFactory.decodeResource(context.getResources(),R.drawable.test3,options);
        mybitmap=Bitmap.createScaledBitmap(b,b.getWidth(),b.getHeight(),true);
        boolean isMutable=mybitmap.isMutable();
        Canvas c=new Canvas(mybitmap);
        ...

這種情況下mybitmap依然是b,因為大小一樣潮孽,就返回了相同的bitmap揪荣。

    /**
     * Creates a new bitmap, scaled from an existing bitmap, when possible. If the
     * specified width and height are the same as the current width and height of
     * the source bitmap, the source bitmap is returned and no new bitmap is
     * created.
     */
    public static Bitmap createScaledBitmap(Bitmap src, int dstWidth, int dstHeight,
            boolean filter) {
        ...
        Bitmap b = Bitmap.createBitmap(src, 0, 0, width, height, m, filter);
        ...
        return b;
    }

參考: 關(guān)于new Canvas(Bitmap)中Bitmap的isMutable的要求PorterDuffXferMode不正確的真正原因PorterDuffXferMode深入試驗) 往史、在android中畫圓形圖片的幾種辦法仗颈、 自定義控件三部曲之繪圖篇(十)——Paint之setXfermode(一)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市椎例,隨后出現(xiàn)的幾起案子挨决,更是在濱河造成了極大的恐慌,老刑警劉巖订歪,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件凰棉,死亡現(xiàn)場離奇詭異,居然都是意外死亡陌粹,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進(jìn)店門福压,熙熙樓的掌柜王于貴愁眉苦臉地迎上來掏秩,“玉大人,你說我怎么就攤上這事荆姆∶苫茫” “怎么了?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵胆筒,是天一觀的道長邮破。 經(jīng)常有香客問我,道長仆救,這世上最難降的妖魔是什么抒和? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮彤蔽,結(jié)果婚禮上摧莽,老公的妹妹穿的比我還像新娘。我一直安慰自己顿痪,他們只是感情好镊辕,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布油够。 她就那樣靜靜地躺著,像睡著了一般征懈。 火紅的嫁衣襯著肌膚如雪石咬。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天卖哎,我揣著相機(jī)與錄音鬼悠,去河邊找鬼。 笑死棉饶,一個胖子當(dāng)著我的面吹牛厦章,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播照藻,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼袜啃,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了幸缕?” 一聲冷哼從身側(cè)響起群发,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎发乔,沒想到半個月后熟妓,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡栏尚,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年起愈,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片译仗。...
    茶點(diǎn)故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡抬虽,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出纵菌,到底是詐尸還是另有隱情阐污,我是刑警寧澤,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布咱圆,位于F島的核電站笛辟,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏序苏。R本人自食惡果不足惜手幢,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望忱详。 院中可真熱鬧弯菊,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至才漆,卻和暖如春牛曹,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背醇滥。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工黎比, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人鸳玩。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓阅虫,卻偏偏與公主長得像,于是被迫代替她去往敵國和親不跟。 傳聞我的和親對象是個殘疾皇子颓帝,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評論 2 345

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