W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗值獎勵
上一節(jié),我們學(xué)習(xí)了Xfermode兩個已經(jīng)過世(過時)的兒子:AvoidXfermode, PixelXorXfermode, 雖然說有點用,但是終歸是被淘汰的了,本節(jié)我們來學(xué)習(xí)Xfermode還健在的三兒子:PorterDuffXfermode;
先祭上官方API文檔:PorterDuffXfermode!文檔內(nèi)容很少,我們可以看到他的構(gòu)造方法:
![]()
參數(shù)只有一個:PorterDuff.Mode mode,而Android給我們提供了16種圖片混排模式,簡單點可以 理解為兩個圖層按照不同模式,可以組合成不同的結(jié)果顯示出來!16種混排模式的結(jié)果圖如下:
![]()
這里兩個圖層:先繪制的圖是目標(biāo)圖(DST),后繪制的圖是源圖(SRC)!
當(dāng)然,在文檔中我們發(fā)現(xiàn)可供使用的模式并不是16種,而是18種,新增了ADD和OVERLAY兩種模式!
嗯,說多也白說,代碼最實際,本節(jié)我們寫下代碼來驗證下這18種模式吧!
PS:這個PorterDuff的命名其實是兩個人名的組合:Tomas Proter和 Tom Duff組成的,他們是最早在 最早在SIGGRAPH上提出圖形混合概念的大神級人物,有興趣的自行百度~
寫個例子來驗證上面的這個圖:
好的,我們來寫個例子驗證下上面這個圖,通過修改不同的模式,來對結(jié)果進(jìn)行對比分析!代碼實現(xiàn):
Step 1:我們先寫個獲取屏幕寬高的工具類吧!ScreenUtil.java:
/** * Created by Jay on 2015/10/23 0023. */ public class ScreenUtil { /** * 獲取屏幕寬高,sdk17后不建議采用 * * @param context */ public static int[] getScreenHW(Context context) { WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); Display display = manager.getDefaultDisplay(); int width = display.getWidth(); int height = display.getHeight(); int[] HW = new int[] { width, height }; return HW; } /** * 獲取屏幕寬高,建議采用 * * @param context */ public static int[] getScreenHW2(Context context) { WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); DisplayMetrics dm = new DisplayMetrics(); manager.getDefaultDisplay().getMetrics(dm); int width = dm.widthPixels; int height = dm.heightPixels; int[] HW = new int[] { width, height }; return HW; } /** * 獲取屏幕的寬度 * * @param context * @return */ public static int getScreenW(Context context) { return getScreenHW2(context)[0]; } /** * 獲取屏幕的高度 * * @param context * @return */ public static int getScreenH(Context context) { return getScreenHW2(context)[1]; } }Step 2:編寫我們的自定義View類,在這里做試驗!XfermodeView.java:
/** * Created by Jay on 2015/10/23 0023. */ public class XfermodeView extends View { private PorterDuffXfermode pdXfermode; //定義PorterDuffXfermode變量 //定義MODE常量,等下直接改這里即可進(jìn)行測試 private static PorterDuff.Mode PD_MODE = PorterDuff.Mode.ADD; private int screenW, screenH; //屏幕寬高 private int width = 200; //繪制的圖片寬高 private int height = 200; private Bitmap srcBitmap, dstBitmap; //上層SRC的Bitmap和下層Dst的Bitmap public XfermodeView(Context context) { this(context, null); } public XfermodeView(Context context, AttributeSet attrs) { super(context, attrs); screenW = ScreenUtil.getScreenW(context); screenH = ScreenUtil.getScreenH(context); //創(chuàng)建一個PorterDuffXfermode對象 pdXfermode = new PorterDuffXfermode(PD_MODE); //實例化兩個Bitmap srcBitmap = makeSrc(width, height); dstBitmap = makeDst(width, height); } public XfermodeView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } //定義一個繪制圓形Bitmap的方法 private Bitmap makeDst(int w, int h) { Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); Canvas c = new Canvas(bm); Paint p = new Paint(Paint.ANTI_ALIAS_FLAG); p.setColor(0xFF26AAD1); c.drawOval(new RectF(0, 0, w * 3 / 4, h * 3 / 4), p); return bm; } //定義一個繪制矩形的Bitmap的方法 private Bitmap makeSrc(int w, int h) { Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); Canvas c = new Canvas(bm); Paint p = new Paint(Paint.ANTI_ALIAS_FLAG); p.setColor(0xFFFFCE43); c.drawRect(w / 3, h / 3, w * 19 / 20, h * 19 / 20, p); return bm; } @Override protected void onDraw(Canvas canvas) { Paint paint = new Paint(); paint.setFilterBitmap(false); paint.setStyle(Paint.Style.FILL); canvas.drawBitmap(srcBitmap, (screenW / 3 - width) / 2, (screenH / 2 - height) / 2, paint); canvas.drawBitmap(dstBitmap, (screenW / 3 - width) / 2 + screenW / 3, (screenH / 2 - height) / 2, paint); //創(chuàng)建一個圖層,在圖層上演示圖形混合后的效果 int sc = canvas.saveLayer(0, 0, screenW, screenH, null, Canvas.MATRIX_SAVE_FLAG | Canvas.CLIP_SAVE_FLAG | Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.FULL_COLOR_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG); canvas.drawBitmap(dstBitmap, (screenW / 3 - width) / 2 + screenW / 3 * 2, (screenH / 2 - height) / 2, paint); //繪制i //設(shè)置Paint的Xfermode paint.setXfermode(pdXfermode); canvas.drawBitmap(srcBitmap, (screenW / 3 - width) / 2 + screenW / 3 * 2, (screenH / 2 - height) / 2, paint); paint.setXfermode(null); // 還原畫布 canvas.restoreToCount(sc); } }代碼看起來好復(fù)雜是吧,其實不然,無非就是獲取了屏幕寬高,然后畫了一個矩形一個圓形, 計算了一下他們的位置,然后設(shè)置下圖層(固定寫法),接著設(shè)下下畫筆setXfermode,接著 繪制到canvas上而已,你看不懂的可能是繪制位置的計算吧,其實不然,位置你喜歡怎么定 都可以!那么接下來我們來一個個看下解果咯,你只需修改PD_MODE的值設(shè)置為不同模式即可!
運行效果圖:
1)PorterDuff.Mode.ADD:
飽和度疊加
2)PorterDuff.Mode.CLEAR:
所繪制不會提交到畫布上,嗯結(jié)果...不知道是為什么了,正常是沒東西的..
3)PorterDuff.Mode.DARKEN:
取兩圖層全部區(qū)域,交集部分顏色加深
4)PorterDuff.Mode.DST:
只保留目標(biāo)圖的alpha和color,所以繪制出來只有目標(biāo)圖
5)PorterDuff.Mode.DST_ATOP:
源圖和目標(biāo)圖相交處繪制目標(biāo)圖,不相交的地方繪制源圖
6)PorterDuff.Mode.DST_IN:
兩者相交的地方繪制目標(biāo)圖,繪制的效果會受到原圖處的透明度影響
7)PorterDuff.Mode.DST_OUT:
在不相交的地方繪制目標(biāo)圖
8)PorterDuff.Mode.DST_OVER:
目標(biāo)圖繪制在上方
9)PorterDuff.Mode.LIGHTEN:
取兩圖層全部區(qū)域,點亮交集部分顏色
10)PorterDuff.Mode.MULTIPLY:
取兩圖層交集部分疊加后顏色
11)PorterDuff.Mode.OVERLAY:
疊加
12)PorterDuff.Mode.SCREEN:
取兩圖層全部區(qū)域,交集部分變?yōu)橥该魃?/p>
13)PorterDuff.Mode.SRC:
只保留源圖像的alpha和color,所以繪制出來只有源圖
14)PorterDuff.Mode.SRC_ATOP:
源圖和目標(biāo)圖相交處繪制源圖,不相交的地方繪制目標(biāo)圖
15)PorterDuff.Mode.SRC_IN:
兩者相交的地方繪制源圖
16)PorterDuff.Mode.SRC_OUT:
不相交的地方繪制源圖
17)PorterDuff.Mode.SRC_OVER:
把源圖繪制在上方
18)PorterDuff.Mode.XOR:
不相交的地方按原樣繪制源圖和目標(biāo)圖
本節(jié)示例代碼下載:
本節(jié)小結(jié):
嗯,本節(jié)就寫了一個簡單的View來驗證這18種不同PorterDuff.Mode下的不同效果, 嘿嘿,蠻耗時間的,不過,讀者看起來肯定清晰多了是吧~當(dāng)然,這只是一些初步的見解!
PorterDuffXfermode的PorterDuff.Mode對于我們自定義控件是非常重要的! 本節(jié)我們初步了解,下節(jié)我們挑幾個例子來練練手!
如果你想看關(guān)于PorterDuff.Mode更加詳細(xì)的介紹可見: Android Paint之 setXfermode PorterDuffXfermode 講解,別人寫的不錯的一篇文章! 嗯,就到這里,明早體檢,今天就寫這么多~
![]()
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: