導(dǎo)航
Paint API之—— Xfermode與PorterDuff全面詳解
Paint API之—— Xfermode與PorterDuff詳解(三)動畫效果
本節(jié)引言:
之前我們學(xué)繪圖的時候講過一個屬性setXfermode(Xfermode xfermode)
:設(shè)置圖形重疊時的處理方式,如合并钦讳,取交集或并集, 經(jīng)常用來制作橡皮的擦除效果枕面!
我們來到官方文檔Xfermode愿卒,我們發(fā)現(xiàn)他有三個兒子:
我們先來講解PorterDuffXfermode這個方法,因?yàn)槠渌麅蓚€已經(jīng)被淘汰潮秘,想看的可以了解一下
三兒子:PorterDuffXfermode
構(gòu)造方法:
參數(shù)只有一個:PorterDuff.Mode mode琼开,而Android給我們提供了16種圖片混排模式,簡單點(diǎn)可以 理解為兩個圖層按照不同模式枕荞,可以組合成不同的結(jié)果顯示出來柜候!16種混排模式的結(jié)果圖如下:
這里兩個圖層:先繪制的圖是目標(biāo)圖(DST),后繪制的圖是源圖(SRC)买猖!
當(dāng)然改橘,在文檔中我們發(fā)現(xiàn)可供使用的模式并不是16種,而是18種玉控,新增了ADD和OVERLAY兩種模式!
嗯飞主,說多也白說,代碼最實(shí)際,本節(jié)我們寫下代碼來驗(yàn)證下這18種模式吧碌识!
PS:這個PorterDuff的命名其實(shí)是兩個人名的組合:Tomas Proter和 Tom Duff組成的碾篡,他們是最早在 最早在SIGGRAPH上提出圖形混合概念的大神級人物,有興趣的自行百度~
寫個例子來驗(yàn)證上面的這個圖:
好的筏餐,我們來寫個例子驗(yàn)證下上面這個圖开泽,通過修改不同的模式,來對結(jié)果進(jìn)行對比分析魁瞪!
代碼實(shí)現(xiàn):
編寫我們的自定義View類穆律,在這里做試驗(yàn)!XfermodeView.java:
public class XfermodeView extends View {
private PorterDuffXfermode pdXfermode; //定義PorterDuffXfermode變量
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);
//創(chuàng)建一個PorterDuffXfermode對象
pdXfermode = new PorterDuffXfermode(PorterDuff.Mode.ADD);
//實(shí)例化兩個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(100,100,w,h),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(100,100,w,h,p);
return bm;
}
@Override
protected void onDraw(Canvas canvas) {
Paint paint = new Paint();
paint.setFilterBitmap(false);
paint.setStyle(Paint.Style.FILL);
//創(chuàng)建一個圖層导俘,在圖層上演示圖形混合后的效果
int sc = 0;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
sc = canvas.saveLayer(new RectF(0,0,width,height),paint);
}
//繪制目標(biāo)圖
canvas.drawBitmap(dstBitmap,0,0, paint); //繪制i
//設(shè)置Paint的Xfermode
paint.setXfermode(pdXfermode);
//繪制源圖
canvas.drawBitmap(srcBitmap, 0,0, paint);
//清除混合模式
paint.setXfermode(null);
// 還原畫布
canvas.restoreToCount(sc);
}
}
然后在布局文件里面布局一下這個自定義的view就可以了
我們來看一下效果
1)PorterDuff.Mode.ADD:飽和度疊加
2)PorterDuff.Mode.CLEAR:
這里圖片是空白峦耘,所以就不貼圖了
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ū)域少梁,點(diǎn)亮交集部分顏色
10)PorterDuff.Mode.MULTIPLY:取兩圖層交集部分疊加后顏色
11)PorterDuff.Mode.OVERLAY:疊加
12)PorterDuff.Mode.SCREEN:取兩圖層全部區(qū)域洛口,交集部分變?yōu)橥该魃?/strong>
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)圖
這只是一個初步的見解第焰,后面我們在深入,下面講一講他的前兩個子類
大兒子:AvoidXfermode
嗯著洼,和前面學(xué)的MaskFilter的兩個子類一樣樟遣,不支持硬件加速,所以如果是API 14以上的版本身笤, 需要關(guān)閉硬件加速才會有效果豹悬!怎么關(guān)自己看上一節(jié)哈~
我們來看看他給我們提供的構(gòu)造方法!
參數(shù)有三個液荸,依次是:
opColor:一個十六進(jìn)制的帶透明度的顏色值瞻佛,比如0x00C4C4;
tolerance:容差值,如果你學(xué)過PS可能用過魔棒工具娇钱,就是設(shè)置選取顏色值的范圍伤柄,比如 容差為0,你選的是純黑的小點(diǎn)文搂,當(dāng)容差調(diào)為40的時候适刀,范圍已經(jīng)擴(kuò)大到大塊黑色這樣!如果 還不是很明白煤蹭,等下我們寫寫代碼就知道了笔喉!
mode:AvoidXfermode模式取视,有兩種:TARGET與AVOID
模式1:AvoidXfermode.Mode.TARGET
該模式會判斷畫布上是否有與我們設(shè)置顏色值一樣的顏色,如果有的話常挚,會把這些區(qū)域 染上一層畫筆定義的顏色作谭,其他地方不染色!下面我們寫代碼演示下奄毡,順便讓大家感覺下 這個容差值折欠!
使用代碼示例:
運(yùn)行效果圖:
嗯,先上下原圖吼过,素材來自gank.io:
接下來我們隨便把墻上某個地方的顏色用顏色取色器取下锐秦,然后寫一個簡單的View!
PS:需要在AndroidManifest.xml中的appliction節(jié)點(diǎn)添加關(guān)閉硬件加速: android:hardwareAccelerated="false"
public class AvoidXfermodeView1 extends View {
private Paint mPaint;
private Bitmap mBitmap;
private AvoidXfermode avoidXfermode;
public AvoidXfermodeView1(Context context) {
super(context);
init();
}
public AvoidXfermodeView1(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public AvoidXfermodeView1(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); //抗鋸齒
avoidXfermode = new AvoidXfermode(0XFFCCD1D4, 0, AvoidXfermode.Mode.TARGET);
mBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.iv_meizi);
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(mBitmap, 50, 50, mPaint);
mPaint.setARGB(255, 222, 83, 71);
mPaint.setXfermode(avoidXfermode);
canvas.drawRect(50, 50, 690, 1010, mPaint);
}
}
運(yùn)行后的效果:
看到墻上那堆姨媽紅了沒,效果杠杠的那先,這里我們的容差值并沒有發(fā)揮作用农猬,我們改一改,把 妹子的白衣服變成姨媽紅售淡!
我們把上面構(gòu)造AvoidXfermode的內(nèi)容改成:
avoidXfermode = new AvoidXfermode(0XFFD9E5F3, 25, AvoidXfermode.Mode.TARGET);
然后,妹子身上的白衣服就變成姨媽紅了...
模式2:AvoidXfermode.Mode.AVOID
和上面的TARGET模式相反慷垮,上面是顏色一樣才改變顏色揖闸,這里是顏色不一樣反而改變顏色, 而容差值同樣帶來相反的結(jié)果料身,容差值為0時汤纸,只有當(dāng)圖片中的像素顏色值與設(shè)置的顏色值完全不一樣 的時候才會被染色,而當(dāng)容差值達(dá)到最大值255的時候芹血,稍微有一點(diǎn)顏色不一樣就會被染色贮泞! 我們只需簡單的修改上面的例子就可以了,同一是修改下構(gòu)造AvoidXfermode的內(nèi)容幔烛! 我們改成下面這句:
avoidXfermode = new AvoidXfermode(0XFFD9E5F3,230, AvoidXfermode.Mode.AVOID);
運(yùn)行效果圖:
二兒子:PixelXorXfermode
這個則是另一種圖像混排模式啃擦,比起大兒子更簡單,他的構(gòu)造方法如下:
參數(shù)解析:
就一個16進(jìn)制帶透明值得顏色值饿悬,至于這個值的作用令蛉,是有一個算法的: PixelXorXfermode內(nèi)部是按照" opColor ^ src ^ dst "這個異或算法運(yùn)算的, 得到一個不透明的(alpha = 255)的色彩值狡恬,設(shè)置到圖像中珠叔!好吧,這是網(wǎng)上搜的 具體我也不知道弟劲,寫個例子試試效果唄~
代碼示例:
運(yùn)行效果圖:
public class PixelXorXfermodeView1 extends View{
private Paint mPaint;
private Bitmap mBitmap;
private PixelXorXfermode pixelxorXfermode;
public PixelXorXfermodeView1(Context context) {
super(context);
init();
}
public PixelXorXfermodeView1(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public PixelXorXfermodeView1(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); //抗鋸齒
pixelxorXfermode = new PixelXorXfermode(0XFFD9E5F3);
mBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.iv_meizi);
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(mBitmap, 50, 50, mPaint);
mPaint.setARGB(255, 222, 83, 71);
mPaint.setXfermode(pixelxorXfermode);
canvas.drawRect(50, 50, 690, 1010, mPaint);
}
}