Paint API之—— Xfermode與PorterDuff全面詳解

導(dǎo)航

Android Paint之顏色過濾器

Paint之shader(圖像渲染)

Paint之PathEffect(路徑效果)

Paint API之—— MaskFilter(面具)

android之繪圖工具類詳解

Paint API之—— Xfermode與PorterDuff全面詳解

Paint API之—— Xfermode與PorterDuff詳解(三)動畫效果

Paint枚舉躬充、常量值觉义、陰影效果惶傻、字體

本節(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種玉控,新增了ADDOVERLAY兩種模式!
嗯飞主,說多也白說,代碼最實(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模式取视,有兩種:TARGETAVOID

模式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);
    }

}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末祷安,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子兔乞,更是在濱河造成了極大的恐慌汇鞭,老刑警劉巖凉唐,帶你破解...
    沈念sama閱讀 222,183評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異虱咧,居然都是意外死亡熊榛,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評論 3 399
  • 文/潘曉璐 我一進(jìn)店門腕巡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來玄坦,“玉大人,你說我怎么就攤上這事绘沉〖彘梗” “怎么了?”我有些...
    開封第一講書人閱讀 168,766評論 0 361
  • 文/不壞的土叔 我叫張陵车伞,是天一觀的道長择懂。 經(jīng)常有香客問我,道長另玖,這世上最難降的妖魔是什么困曙? 我笑而不...
    開封第一講書人閱讀 59,854評論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮谦去,結(jié)果婚禮上慷丽,老公的妹妹穿的比我還像新娘。我一直安慰自己鳄哭,他們只是感情好要糊,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,871評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著妆丘,像睡著了一般锄俄。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上勺拣,一...
    開封第一講書人閱讀 52,457評論 1 311
  • 那天奶赠,我揣著相機(jī)與錄音,去河邊找鬼宣脉。 笑死车柠,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的塑猖。 我是一名探鬼主播竹祷,決...
    沈念sama閱讀 40,999評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼羊苟!你這毒婦竟也來了塑陵?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,914評論 0 277
  • 序言:老撾萬榮一對情侶失蹤蜡励,失蹤者是張志新(化名)和其女友劉穎令花,沒想到半個月后阻桅,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,465評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡兼都,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,543評論 3 342
  • 正文 我和宋清朗相戀三年嫂沉,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片扮碧。...
    茶點(diǎn)故事閱讀 40,675評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡趟章,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出慎王,到底是詐尸還是另有隱情蚓土,我是刑警寧澤,帶...
    沈念sama閱讀 36,354評論 5 351
  • 正文 年R本政府宣布赖淤,位于F島的核電站蜀漆,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏咱旱。R本人自食惡果不足惜确丢,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,029評論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望吐限。 院中可真熱鬧蠕嫁,春花似錦、人聲如沸毯盈。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,514評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽搂赋。三九已至,卻和暖如春益缠,著一層夾襖步出監(jiān)牢的瞬間脑奠,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,616評論 1 274
  • 我被黑心中介騙來泰國打工幅慌, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留宋欺,地道東北人。 一個月前我還...
    沈念sama閱讀 49,091評論 3 378
  • 正文 我出身青樓胰伍,卻偏偏與公主長得像齿诞,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子骂租,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,685評論 2 360

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