自定义View之基础篇——PorterDuff

前言

本章主要介绍颜色渲染器PorterDuff。

PorterDuff其实来自两个人名:Tomas Porter和Tom Duff利用PorterDuff.Mode,我们可以实现图片的任意叠加混合,eg.实现画图中的橡皮擦功能、显示圆形图片等等

 

1、核心代码

以圆和矩形为例。dst为下层,是先画的图形(这里我选择的是灰色的圆);src为上层,后画的图形(我选用的是蓝色矩形)。实验时,设置的圆的直径与矩形宽高相等,这样重叠起来方便看效果。

(1)核心代码1(直接用canvas绘制):

int sc = canvas.saveLayer(0, 0, canvas.getWidth(), canvas.getHeight(), null, Canvas.ALL_SAVE_FLAG);//创建一个新的layer
// canvas.drawARGB(255, 139, 197, 186);//画布颜色

//先绘制一个下层图像
canvas.drawCircle(100,100,100,dstPaint);

//绘制上层图像
PorterDuffXfermode mode = new PorterDuffXfermode(PorterDuff.Mode.CLEAR);
srcPaint.setXfermode(mode);
// canvas.drawRect(new Rect(0,0,200,200),srcPaint);//圆和矩形位置重叠
canvas.drawRect(new Rect(100,100,300,300),srcPaint);//圆和矩形位置稍有偏移

srcPaint.setXfermode(null); // 还原混合模式
canvas.restoreToCount(sc);  // 将这个layer绘制到canvas默认的layer

注意蓝色代码:

 

 int sc = canvas.saveLayer(0, 0, canvas.getWidth(), canvas.getHeight(), null, Canvas.ALL_SAVE_FLAG);//创建一个新的layer

 srcPaint.setXfermode(null); // 还原混合模式

 canvas.restoreToCount(sc);  // 将这个layer绘制到canvas默认的layer

    这段代码最好加上,否则某些模式下原本不该显示的地方出现白色填充。特别是如果设置了画布颜色,效果会很明显,eg.CLEAR,会显示一个灰色圆和白色矩形(除非新建一个图层,也就是上面这点代码,这样就可以变成原来的效果)。具体原因参见 Android中Canvas绘图之PorterDuffXfermode使用及工作原理详解 or Android PorterDuffXfermode使用中的一些坑

 

(2)核心代码2(使用Bitmap绘制)

 

int sc = canvas.saveLayer(0, 0, canvas.getWidth(), canvas.getHeight(), null, Canvas.ALL_SAVE_FLAG);//创建一个新的layer

Bitmap dstBm= Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Bitmap.Config.ARGB_8888);
Bitmap srcBm= Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Bitmap.Config.ARGB_8888);

Canvas dstCanvas = new Canvas(dstBm);//将画布内容转换为bitmap
Canvas srcCanvas= new Canvas(srcBm);

//先绘制一个下层图像
dstCanvas .drawCircle(100,100,100,dstPaint);
canvas.drawBitmap(dstBm,0,0,dstPaint);

//绘制上层图像
srcCanvas.drawRect(new Rect(100,100,300,300),srcPaint);//圆和矩形位置稍有偏移

PorterDuffXfermode mode = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);
srcPaint.setXfermode(mode);
// canvas.drawRect(new Rect(0,0,200,200),srcPaint);//圆和矩形位置重叠
canvas.drawBitmap(srcBm,0,0,srcPaint); 

(3)重点说明

    对于网上疯传的下面两种不同模式图,本人亲测,双方各有道理。只不过,前者是用采用canvas直接绘图导致的;后者是官方推荐的一种写法,也就是上下层均用bitmap实现。本文将就上述两种方法,分别进行测试。

自定义View之基础篇——PorterDuff_第1张图片

纠正一下,CLEAR效果两个方式得到的都一样。不一样的是:SRC、SRC_IN、DST_IN、SRC_OUT、DST_ATOP、MULTIPLY这六个,本文会在第三点进行比对显示,方便区分。

 

2、使用canvas直接画图

2.1 总结

橙色部分为两种方法的不同地方。

PorterDuff.Mode

 

说明

 

SRC

 

显示上层区域;若此时下层区域存在没有被上层图像覆盖的部分,也会显示

 

DST

 

仅显示下层绘制,上层不绘制

 

SRC_OVER

 

正常显示,但上层居上显示

 

DST_OVER

 

正常显示,但下层居上显示

 

SRC_IN

 

显示下层,并将交集部分替换成上层(上层交集部分嵌入到下层)

 

DST_IN

 

仅显示下层,同DST

 

SRC_OUT

 

取非交集部分(将上层的交集部分挖出)

 

DST_OUT

 

取下层非交集部分

 

SRC_ATOP 

 

显示下层,并将交集部分替换成上层,同SRC_IN

 

DST_ATOP

 

正常显示,下层居上显示,同DST_OVER

 

XOR

 

去除交集区域

 

DARKEN

 

取两层全部区域,交集区域变暗【必须关闭硬件加速】

 

LIGHTEN

 

取两层全部区域,交集区域变亮【必须关闭硬件加速】

MULIPLY

 

取下层全部区域,交集区域色彩叠加

 

SCREEN

 

取两层全部区域,交集部分变为透明色

 

CLEAR

 

取下层非交集部分

 

 

2.2具体分析

特别说明:由于我的界面背景设置成白色,所以下面图中原本透明的地方就显示成了白色,如果设置成其他颜色也会随之响应改变。

 

(1)SRC

①圆和矩形位置刚好重叠的时候

自定义View之基础篇——PorterDuff_第2张图片

②圆和矩形稍有偏移时

自定义View之基础篇——PorterDuff_第3张图片

 

(2)DST

①圆和矩形位置刚好重叠的时候

   自定义View之基础篇——PorterDuff_第4张图片

②圆和矩形稍有偏移时

自定义View之基础篇——PorterDuff_第5张图片

 

 

(3)SRC_OVER

自定义View之基础篇——PorterDuff_第6张图片

自定义View之基础篇——PorterDuff_第7张图片

 

 

 

(4)DST_OVER

自定义View之基础篇——PorterDuff_第8张图片

自定义View之基础篇——PorterDuff_第9张图片

 

(5)SRC_IN

自定义View之基础篇——PorterDuff_第10张图片

自定义View之基础篇——PorterDuff_第11张图片

 

(6)DST_IN

自定义View之基础篇——PorterDuff_第12张图片

自定义View之基础篇——PorterDuff_第13张图片

 

(7)SRC_OUT

自定义View之基础篇——PorterDuff_第14张图片

自定义View之基础篇——PorterDuff_第15张图片

 

(8)DST_OUT

自定义View之基础篇——PorterDuff_第16张图片

自定义View之基础篇——PorterDuff_第17张图片

 

(8)SRC_ATOP

 

自定义View之基础篇——PorterDuff_第18张图片

自定义View之基础篇——PorterDuff_第19张图片

 

(9)DST_ATOP

自定义View之基础篇——PorterDuff_第20张图片

自定义View之基础篇——PorterDuff_第21张图片

 

(10)XOR

自定义View之基础篇——PorterDuff_第22张图片

自定义View之基础篇——PorterDuff_第23张图片

 

(11)DARKEN

无效果。原因:需要关闭硬件加速

①未关闭前

自定义View之基础篇——PorterDuff_第24张图片

自定义View之基础篇——PorterDuff_第25张图片

②关闭后

自定义View之基础篇——PorterDuff_第26张图片         自定义View之基础篇——PorterDuff_第27张图片         

 

 

关闭硬件加速的代码:

if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB){
    //View从API Level 11才加入setLayerType方法
    //关闭硬件加速
    setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}

 

(12)LIGHTEN

无明显效果。原因:需要关闭硬件加速

①未关闭前

自定义View之基础篇——PorterDuff_第28张图片

自定义View之基础篇——PorterDuff_第29张图片

②关闭后

自定义View之基础篇——PorterDuff_第30张图片          自定义View之基础篇——PorterDuff_第31张图片


(13)MULIPLY

自定义View之基础篇——PorterDuff_第32张图片

自定义View之基础篇——PorterDuff_第33张图片

(14)SCREEN    

滤色模式。

自定义View之基础篇——PorterDuff_第34张图片

自定义View之基础篇——PorterDuff_第35张图片

(15)CLEAR

 

自定义View之基础篇——PorterDuff_第36张图片

自定义View之基础篇——PorterDuff_第37张图片

 

 

3、使用Bitmap绘图

 

特别说明:由于我的界面背景设置成白色,所以下面图中原本透明的地方就显示成了白色,如果设置成其他颜色也会随之响应改变。

一定是要两个都用bitmap绘制。

 

3.1总结

橙色部分为两种方法的不同地方。

 

PorterDuff.Mode

说明

SRC

仅显示上层区域

DST

仅显示下层绘制,上层不绘制

SRC_OVER

正常显示,但上层居上显示

DST_OVER

正常显示,但下层居上显示

SRC_IN

仅显示上层交集部分

DST_IN

仅显示下层交集部分

SRC_OUT

取上层非交集部分

DST_OUT

取下层非交集部分

SRC_ATOP 

显示下层,并将交集部分替换成上层,同SRC_IN

DST_ATOP

显示上层,并将交集部分替换成下层(下层交集部分嵌入到上层)

XOR

去除交集区域

DARKEN

取两层全部区域,交集区域变暗

LIGHTEN

取两层全部区域,交集区域变亮

MULIPLY

取交集部分叠加后颜色

SCREEN

取两层全部区域,交集部分变为透明色

CLEAR

取下层非交集部分

 

3.2具体分析             

下面主要就两个方式的不同之处进行实验(下面的(1)(5)...没顺序,方便快速找到另一种方法的模式位置)。

(1)SRC

自定义View之基础篇——PorterDuff_第38张图片

 

(5)SRC_IN

自定义View之基础篇——PorterDuff_第39张图片

 

(6)DST_IN

自定义View之基础篇——PorterDuff_第40张图片

 

(7)SRC_OUT

自定义View之基础篇——PorterDuff_第41张图片

(9)DST_ATOP

自定义View之基础篇——PorterDuff_第42张图片

 

(13)MULIPLY

自定义View之基础篇——PorterDuff_第43张图片

 

4、参考


各个击破搞明白PorterDuff.Mode    ☆☆☆内含一些特殊情况,待实验测试

有坑?? 为何wing坠入PorterDuffXferMode的万丈深渊(PorterDuffXferMode深入试验)   ☆☆☆☆

PorterDuffXferMode不正确的真正原因PorterDuffXferMode深入试验)     ☆☆☆☆罗列了许多常见问题

 

Android 自定义View学习(五)——Paint 关于PorterDuffXfermode学习       ☆☆☆内含一些demo包括圆形图片,值得学习

 

Android PorterDuffXfermode使用中的一些坑           ☆☆☆内含一些现象的分析

Android中Canvas绘图之PorterDuffXfermode使用及工作原理详解  ☆☆☆一些问题分析

 

 

PorterDuffXfermode 正确使用方式(详解)    -----内含代码分析

android PorterDuffXferMode真正的效果测试集合(对比官方demo)

Android 颜色渲染PorterDuff及Xfermode详解

 

 

 

 

 

 

 

 

注意这段代码:

你可能感兴趣的:(自定义控件)