转载自:http://blog.csdn.net/allen315410/article/details/45077165
上篇博客中,我将我对Paint的ColorFilter相关的几个子类以及用法做了总结,其中最常用的ColorMatrixColorFilter值得我们多学习学习,通过定义一个color值的4*5的矩阵,来设置Paint的各种各样的变色效果。此外,还有PorterDuffColorFilter,其实用的并不是很多,但是PorterDuffColorFilter中使用的几个概念尤其重要,我们要好好了解一下,PorterDuff是老外发明的一直图形混合模式,并且Android 的API中为我们提供了18种不同的混合模式算法,我们平时在开发的时候需要了解这些模式分别代表的含义和用法,就是灵活的运用这些模式随意混合出我们需要的图像效果。
Xfermode
Xfermode具体怎么翻译,说实话,我也不知道,我习惯叫它图片混合模式,随便了,管它叫什么,不妨碍我们使用它。关于Xfermode的说明,可以在Google文档中找到这样的描述:Xfermode是在绘图通道中自定义“传输模式”的基类。静态函数创建可以调用或者返回任意作为模式枚举指定的预定义子类实例。当Xfermode分配给Paint,然后绘制对象与Paint就具备了所添加的xfermode。读起来比较拗口,下面直接看Xfermode的源码:
- public class Xfermode {
- protected void finalize() throws Throwable {
- try {
- finalizer(native_instance);
- } finally {
- super.finalize();
- }
- }
- private static native void finalizer(long native_instance);
- long native_instance;
- }
查看一下文档发现Xfermode确实有AvoidXfermode、PixelXorXfermode、PorterDuffXfermode,下面来继续学习一下3个子类的用法。
AvoidXfermode
看这个子类之前告诉大家一个不幸的消息,AvoidXfermode不支持硬件加速,在高于API16的机器上不会适用,如果想测试这个子类,1,可以关闭手机的硬件加速模块;2,在AndroidManifest.xml中Application节点上设置硬件加速为false。- android:hardwareAccelerated="false"
- public AvoidXfermode(int opColor, int tolerance, Mode mode)
AvoidXfermode.Mode.TARGET
在该模式下Android会判断画布上的颜色是否会有跟opColor不一样的颜色,比如我opColor是红色,那么在TARGET模式下就会去判断我们的画布上是否有存在红色的地方,如果有,则把该区域“染”上一层我们画笔定义的颜色,否则不“染”色,而tolerance容差值则表示画布上的像素和我们定义的红色之间的差别该是多少的时候才去“染”的,比如当前画布有一个像素的色值是(200, 20, 13),而我们的红色值为(255, 0, 0),当tolerance容差值为255时,即便(200, 20, 13)并不等于红色值也会被“染”色,容差值越大“染”色范围越广反之则反,空说无凭我们来看看具体的实现和效果:- public class CustomView3 extends View {
- private Paint mPaint;
- private Bitmap mBitmap;
- private Context mContext;
- private int x, y, w, h;
- private AvoidXfermode avoidXfermode;
- public CustomView3(Context context) {
- this(context, null);
- }
- public CustomView3(Context context, AttributeSet attrs) {
- super(context, attrs);
- mContext = context;
- initRes();
- initPaint();
- }
- private void initRes() {
- //加载bitmap
- mBitmap = BitmapFactory.decodeResource(mContext.getResources(), R.mipmap.image);
- //获取bitmap的展示起始布局
- x = ScreenUtil.getScreenW(mContext) / 2 - mBitmap.getWidth() / 2;
- y = ScreenUtil.getScreenH(mContext) / 2 - mBitmap.getHeight() / 2;
- w = ScreenUtil.getScreenW(mContext) / 2 + mBitmap.getWidth() / 2;
- h = ScreenUtil.getScreenH(mContext) / 2 + mBitmap.getHeight() / 2;
- }
- private void initPaint() {
- mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- avoidXfermode = new AvoidXfermode(0XFFFFFFFF, 0, AvoidXfermode.Mode.TARGET);
- }
- @Override
- protected void onDraw(Canvas canvas) {
- canvas.drawBitmap(mBitmap, x, y, mPaint);
- mPaint.setARGB(255, 211, 53, 243);
- mPaint.setXfermode(avoidXfermode);
- canvas.drawRect(x, y, w, h, mPaint);
- }
- }
AvoidXfermode(0XFFFFFFFF, 0, AvoidXfermode.Mode.TARGET):
大家可以看到,在我们的模式为TARGET容差值为0的时候此时只有当图片中像色颜色值为0XFFFFFFFF的地方才会被染色,而其他地方不会有改变
下面我们来修改一下容差值,将容差值改成255:
AvoidXfermode(0XFFFFFFFF, 255, AvoidXfermode.Mode.TARGET)
而当容差值为255的时候只要是跟0XFFFFFFFF有点接近的地方都会被染色
AvoidXfermode.Mode.AVOID
AvoidXfermode(0XFFFFFFFF, 0, AvoidXfermode.Mode.AVOID):
AvoidXfermode(0XFFFFFFFF, 255, AvoidXfermode.Mode.AVOID):
当容差值为255时,只要与0XFFFFFFFF稍微有点不一样的地方就会被染色
那么这玩意究竟有什么用呢?比如说当我们只想在白色的区域画点东西或者想把白色区域的地方替换为另一张图片的时候就可以采取这种方式!
PixelXorXfermode
PixelXorXfermode是Xfermode下的另外一种图像混排模式,该类特别简单,不过呢,也很不幸的,在API16中已经过时了。我们来做一个简单的了解,先看PixelXorXfermode的构造方法:
- public PixelXorXfermode(int opColor)
- public class CustomView3 extends View {
- private Paint mPaint;
- private Bitmap mBitmap;
- private Context mContext;
- private int x, y, w, h;
- private PixelXorXfermode pixelXorXfermode;
- public CustomView3(Context context) {
- this(context, null);
- }
- public CustomView3(Context context, AttributeSet attrs) {
- super(context, attrs);
- mContext = context;
- initRes();
- initPaint();
- }
- private void initRes() {
- //加载bitmap
- mBitmap = BitmapFactory.decodeResource(mContext.getResources(), R.mipmap.image);
- //获取bitmap的展示起始布局
- x = ScreenUtil.getScreenW(mContext) / 2 - mBitmap.getWidth() / 2;
- y = ScreenUtil.getScreenH(mContext) / 2 - mBitmap.getHeight() / 2;
- w = ScreenUtil.getScreenW(mContext) / 2 + mBitmap.getWidth() / 2;
- h = ScreenUtil.getScreenH(mContext) / 2 + mBitmap.getHeight() / 2;
- }
- private void initPaint() {
- mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- pixelXorXfermode = new PixelXorXfermode(0XFFFF0000);
- }
- @Override
- protected void onDraw(Canvas canvas) {
- //先绘制Bitmap,src
- canvas.drawBitmap(mBitmap, x, y, mPaint);
- //随便设置一个纯色测试
- mPaint.setARGB(255, 211, 53, 243);
- //设置Xfermode
- mPaint.setXfermode(pixelXorXfermode);
- //在bitmap上混排一个纯色的矩形(dst)
- canvas.drawRect(x, y, w, h, mPaint);
- }
- }
PixelXorXfermode在底层已经取出src,dst每个像素点与opColor进行了opColor ^ src ^ dst运算了,结果输出就是上图所示的那样!好了,我只学这么多了,因为它已经过时了,同样上面的AvoidXfermode也是,过时了,了解即可。下面是对Xfermode的第三个子类,也是唯一一个还没有过时的,非常重要的子类PorterDuffXfermode的学习。
PorterDuffXfermode
- public PorterDuffXfermode(PorterDuff.Mode mode)
- public class XfermodeView extends View {
- //PorterDuff模式常量 可以在此更改不同的模式测试
- private static final PorterDuff.Mode MODE = PorterDuff.Mode.CLEAR;
- private PorterDuffXfermode porterDuffXfermode;
- private int screenW, screenH; //屏幕宽高
- private Bitmap srcBitmap, dstBitmap;
- //源图和目标图宽高
- private int width = 120;
- private int height = 120;
- public XfermodeView(Context context) {
- this(context, null);
- }
- public XfermodeView(Context context, AttributeSet attrs) {
- super(context, attrs);
- screenW = ScreenUtil.getScreenW((Activity) context);
- screenH = ScreenUtil.getScreenH((Activity) context);
- //创建一个PorterDuffXfermode对象
- porterDuffXfermode = new PorterDuffXfermode(MODE);
- //创建原图和目标图
- srcBitmap = makeSrc(width, height);
- dstBitmap = makeDst(width, height);
- }
- //创建一个圆形bitmap,作为dst图
- 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(0xFFFFCC44);
- c.drawOval(new RectF(0, 0, w * 3 / 4, h * 3 / 4), p);
- return bm;
- }
- // 创建一个矩形bitmap,作为src图
- 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(0xFF66AAFF);
- 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);
- //绘制“src”蓝色矩形原图
- canvas.drawBitmap(srcBitmap, screenW / 8 - width / 4, screenH / 12 - height / 4, paint);
- //绘制“dst”黄色圆形原图
- canvas.drawBitmap(dstBitmap, screenW / 2, screenH / 12, paint);
- //创建一个图层,在图层上演示图形混合后的效果
- 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);
- //先绘制“dst”黄色圆形
- canvas.drawBitmap(dstBitmap, screenW / 4, screenH / 3, paint);
- //设置Paint的Xfermode
- paint.setXfermode(porterDuffXfermode);
- canvas.drawBitmap(srcBitmap, screenW / 4, screenH / 3, paint);
- paint.setXfermode(null);
- // 还原画布
- canvas.restoreToCount(sc);
- }
- }
1.PorterDuff.Mode.CLEAR。中文描述:所绘制源图像不会提交到画布上。
- private static final PorterDuff.Mode MODE = PorterDuff.Mode.CLEAR;
2.PorterDuff.Mode.SRC。中文描述:只显示源图像。
- private static final PorterDuff.Mode MODE = PorterDuff.Mode.SRC;
3.PorterDuff.Mode.DST。中文描述:只显示目标图像。
- private static final PorterDuff.Mode MODE = PorterDuff.Mode.DST;
4.PorterDuff.Mode.SRC_OVER。中文描述:正常绘制显示,源图像居上显示。
- private static final PorterDuff.Mode MODE = PorterDuff.Mode.SRC_OVER;
5.PorterDuff.Mode.DST_OVER。中文描述: 上下层都显示。目标图像居上显示。
- private static final PorterDuff.Mode MODE = PorterDuff.Mode.DST_OVER;
6.PorterDuff.Mode.SRC_IN。中文描述: 取两层绘制交集中的源图像。
- private static final PorterDuff.Mode MODE = PorterDuff.Mode.SRC_IN;
7.PorterDuff.Mode.DST_IN。中文描述:取两层绘制交集中的目标图像。
- private static final PorterDuff.Mode MODE = PorterDuff.Mode.DST_IN;
8.PorterDuff.Mode.SRC_OUT。中文描述:只在源图像和目标图像不相交的地方绘制源图像。
- private static final PorterDuff.Mode MODE = PorterDuff.Mode.SRC_OUT;
9.PorterDuff.Mode.DST_OUT。中文描述:只在源图像和目标图像不相交的地方绘制目标图像。
- private static final PorterDuff.Mode MODE = PorterDuff.Mode.DST_OUT;
10.PorterDuff.Mode.SRC_ATOP。中文描述:在源图像和目标图像相交的地方绘制源图像,在不相交的地方绘制目标图像。
- private static final PorterDuff.Mode MODE = PorterDuff.Mode.SRC_ATOP;
11.PorterDuff.Mode.DST_ATOP。中文描述:在源图像和目标图像相交的地方绘制目标图像而在不相交的地方绘制源图像。
- private static final PorterDuff.Mode MODE = PorterDuff.Mode.DST_ATOP;
12.PorterDuff.Mode.XOR。中文描述:异或:去除两图层交集部分
- private static final PorterDuff.Mode MODE = PorterDuff.Mode.XOR;
13.PorterDuff.Mode.DARKEN。中文描述:取两图层全部区域,交集部分颜色加深
- private static final PorterDuff.Mode MODE = PorterDuff.Mode.DARKEN;
14.PorterDuff.Mode.LIGHTEN。中文描述:取两图层全部,点亮交集部分颜色
- private static final PorterDuff.Mode MODE = PorterDuff.Mode.LIGHTEN;
15.PorterDuff.Mode.MULTIPLY。中文描述:取两图层交集部分叠加后颜色
- private static final PorterDuff.Mode MODE = PorterDuff.Mode.MULTIPLY;
16.PorterDuff.Mode.SCREEN。中文描述:滤色。
- private static final PorterDuff.Mode MODE = PorterDuff.Mode.SCREEN;
以下是android中新加的两种模式:
17.ADD。中文描述:饱和度相加。
- private static final PorterDuff.Mode MODE = PorterDuff.Mode.ADD;
18.OVERLAY。中文描述:叠加
- private static final PorterDuff.Mode MODE = PorterDuff.Mode.OVERLAY;