先上一张随处可见的图片:
从上面我们可以看到PorterDuff.Mode为枚举类,一共有16个枚举值:
- | - | - |
---|---|---|
1 | PorterDuff.Mode.CLEAR | 所绘制不会提交到画布上 |
2 | PorterDuff.Mode.SRC | 显示上层绘制图片 |
3 | PorterDuff.Mode.DST | 显示下层绘制图片 |
4 | PorterDuff.Mode.SRC_OVER | 正常绘制显示,上下层绘制叠盖 |
5 | PorterDuff.Mode.DST_OVER | 上下层都显示。下层居上显示 |
6 | PorterDuff.Mode.SRC_IN | 取两层绘制交集。显示上层 |
7 | PorterDuff.Mode.DST_IN | 取两层绘制交集。显示下层 |
8 | PorterDuff.Mode.SRC_OUT | 取上层绘制非交集部分 |
9 | PorterDuff.Mode.DST_OUT | 取下层绘制非交集部 |
10 | PorterDuff.Mode.SRC_ATOP | 取下层非交集部分与上层交集部分 |
11 | PorterDuff.Mode.DST_ATOP | 取上层非交集部分与下层交集部分 |
12 | PorterDuff.Mode.XOR | 异或:去除两图层交集部分 |
13 | PorterDuff.Mode.DARKEN | 取两图层全部区域,交集部分颜色加深 |
14 | PorterDuff.Mode.LIGHTEN | 取两图层全部,点亮交集部分颜色 |
15 | PorterDuff.Mode.MULTIPLY | 取两图层交集部分叠加后颜色 |
16 | PorterDuff.Mode.SCREEN | 取两图层全部区域,交集部分变为透明色 |
橡皮擦,这是个好方法啊,看看。
可以通过修改Paint
的Xfermode
来影响在Canvas
已有的图像上面绘制新的颜色的方式。
在正常的情况下,在已有的图像上绘图将会在其上面添加一层新的形状。如果新的Paint
是完全不透明的,那么它将完全遮挡住下面的Paint
;如果它是部分透明的,那么它将会被染上下面的颜色。下面的Xfermode
子类可以改变这种行为:
1)
AvoidXfermode
指定了一个颜色和容差,强制Paint避免在它上面绘图(或者只在它上面绘图)。
2)PixelXorXfermode
当覆盖已有的颜色时,应用一个简单的像素XOR操作。
3)PorterDuffXfermode
这是一个非常强大的转换模式,使用它,可以使用图像合成的16条Porter-Duff规则的任意一条来控制Paint如何与已有的Canvas图像进行交互。
要应用转换模式,可以使用setXferMode
方法,如下所示:
1 AvoidXfermode avoid = new AvoidXfermode(Color.BLUE, 10, AvoidXfermode.Mode. AVOID);
2 borderPen.setXfermode(avoid);
这里可以实现完美的橡皮擦功能!代码异常简单:
1 Xfermode xFermode = new PorterDuffXfermode(PorterDuff.Mode.CLEAR);
2 paint.setXfermode(xFermode);
引用:
Android Xfermode 实战 实现圆形、圆角图片 - Hongyang - 博客频道 - CSDN.NET
Android 颜色渲染(九) PorterDuff及Xfermode详解 - Whatever is worth doing is worth doing well. - 博客频道 - CSDN.NET
Android Paint之 setXfermode PorterDuffXfermode 讲解 - Ajian_studio - 博客频道 - CSDN.NET
使用PorterDuffXfermode实现遮罩层磊神仙新浪博客
在Paint—1—简介 的Paint方法中有这样一个方法:
setXfermode(Xfermode xfermode):设置图形重叠时的处理方式,如合并,取交集或并集, 经常用来制作橡皮的擦除效果!
/**
* Set or clear the xfermode object. - 设置或清除xfermode对象;
* Pass null to clear any previous xfermode. - 传递null以清除任何以前的xfermode。
* As a convenience, the parameter passed is also returned. - 为方便起见,也返回传递的参数。
*
* @return xfermode
*/
public Xfermode setXfermode(Xfermode xfermode) {
int xfermodeNative = 0;
if (xfermode != null)
xfermodeNative = xfermode.native_instance;
native_setXfermode(mNativePaint, xfermodeNative);
mXfermode = xfermode;
return xfermode;
}
这个方法传进一个 Xfermode 对象,而打开 Xfermode 发现里面没有提供任何可用的构造函数或方法,ctrl +T 看到它有三个子类:
API—AvoidXfermode | Android 开发者
API—PixelXorXfermode | Android 开发者
API—PorterDuffXfermode | Android 开发者
Xfermode 的官方介绍
/** This xfermode draws, or doesn't draw, based on the destination's
* distance from an op-color.
*
* There are two modes, and each mode interprets a tolerance value.
*
* Avoid: In this mode, drawing is allowed only on destination pixels that
* are different from the op-color.
* Tolerance near 0: avoid any colors even remotely similar to the op-color
* Tolerance near 255: avoid only colors nearly identical to the op-color
* Tolerance near 0: draw only on colors that are nearly identical to the op-color
* Tolerance near 255: draw on any colors even remotely similar to the op-color
*/
public AvoidXfermode(int opColor, int tolerance, Mode mode) {
if (tolerance < 0 || tolerance > 255) {
throw new IllegalArgumentException("tolerance must be 0..255");
}
native_instance = nativeCreate(opColor, tolerance, mode.nativeInt);
}
咱们把它上面的说明看下就很清楚了:
xfermode 是否绘制,基于目标色和参数 op-color 的差距;
其中有两种模式,分别为 Avoid 和 TARGET:
Avoid模式:只会在目标像素值和 op-color “不一样” 的地方进行绘制;
Target模式:只会在目标像素值和 op-color “一样” 的地方进行绘制;
上面的”一样” 和 “不一样” 我都打上了引号,并不是指严格意义上的一样,而是只要在可容忍范围内就代表一样,这个可容忍范围,就是容差值(tolerance),0 代表最小容差,即得和 op-color 真正意义上一样才 ok ,255 则代表最大容差,只要有一点相近,则ok;
下面来一一介绍:
AvoidXfermode
构造方法:
参数有三个,依次是:
opColor:一个十六进制的带透明度的颜色值,比如0x00C4C4;
tolerance:容差值,如果你学过PS可能用过魔棒工具,就是设置选取颜色值的范围,比如 容差为0,你选的是纯黑的小点,当容差调为40的时候,范围已经扩大到大块黑色这样!如果 还不是很明白,等下我们写写代码就知道了!
mode:AvoidXfermode模式,有两种:TARGET与AVOID
模式1:AvoidXfermode.Mode.TARGET
在该模式下Android会判断画布上的颜色是否会有跟opColor不一样的颜色,比如我opColor是红色,那么在TARGET模式下就会去判断我们的画布上是否有存在红色的地方,如果有,则把该区域“染”上一层我们画笔定义的颜色,否则不“染”色,而tolerance容差值则表示画布上的像素和我们定义的红色之间的差别该是多少的时候才去“染”的,比如当前画布有一个像素的色值是(200,20, 13),而我们的红色值为(255, 0, 0),当tolerance容差值为255时,即便(200, 20,
13)并不等于红色值也会被“染”色,容差值越大“染”色范围越广反之则反,空说无凭我们来看看具体的实现和效果:
先看素材图:
写一个简单的View:
//AvoidXfermode
public class TestPaintViewAvoidXfermode extends View {
private Paint mPaint;
private Bitmap mBitmap;
private AvoidXfermode avoidXfermode;
public TestPaintViewAvoidXfermode(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); //抗锯齿
avoidXfermode = new AvoidXfermode(Color.BLUE, 100, AvoidXfermode.Mode.TARGET);
mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.test_drawable);
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(mBitmap, 50, 50, mPaint);
mPaint.setColor(Color.RED);
mPaint.setXfermode(avoidXfermode);
canvas.drawRect(50, 50, 690, 1010, mPaint);
}
}
运行后的效果:
我擦,什么情况,逗我玩儿呢?这时候大家别忘了,前面说过这方法已经在API 16过时了,要在高版本用的话需要关掉硬件加速,什么?硬件加速怎么关…
硬件加速分全局(Application)、Activity、Window、View 四个层级,也简单提及一下:
1.在AndroidManifest.xml文件为application标签添加如下的属性即可为整个应用程序开启硬件加速:
<application android:hardwareAccelerated="true" ...>
2.在Activity 标签下使用 hardwareAccelerated 属性开启或关闭硬件加速:
<activity android:hardwareAccelerated="false" />
3.在Window 层级使用如下代码开启硬件加速:
getWindow().setFlags( WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED, WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
4.View 级别如下关闭硬件加速,view 层级上没法单独开启硬件加速:
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
好了,原来如此,咱们直接在全局application 关闭硬件加速:
<application
android:allowBackup="true"
android:hardwareAccelerated="false"---
再看下效果:
模式2:AvoidXfermode.Mode.AVOID
和上面的TARGET模式相反,上面是颜色一样才改变颜色,这里是颜色不一样反而改变颜色,
而容差值同样带来相反的结果,容差值为0时,只有当图片中的像素颜色值与设置的颜色值完全不一样
的时候才会被染色,而当容差值达到最大值255的时候,稍微有一点颜色不一样就会被染色!
我们可以看到,现在蓝花已经变成红花了,已经实现了前面说的图标变色小需求,这时候有人可能会说了,这东西还有点用,如果我要在进行某些操作的时候让图标进行颜色的平滑过渡,该怎么办呢?比如viewPager从一页滑到另一页的时候,图标颜色渐变过渡,其实这样的需求只需要在上面的基础上稍加改动即可,提供下思路:
eg:view层级对外提供个接口,传入渐变比例,view里根据比例计算出当前色值,然后实时的把paint的色值更新,重新绘制即可!
好了,AvoidXfermode 就讲这些!
PixelXorXfermode
/**
* PixelXorXfermode implements a simple pixel xor (op ^ src ^ dst).
* This transformation does not follow premultiplied conventions, therefore
* this mode *always* returns an opaque color (alpha == 255). Thus it is
* not really usefull for operating on blended colors.
*/
@Deprecated
public class PixelXorXfermode extends Xfermode {
public PixelXorXfermode(int opColor) {
native_instance = nativeCreate(opColor);
}
private static native int nativeCreate(int opColor);
}
从上面的介绍上讲,这只是一个简单异或运算,这种变换不满足预乘公约,因此会总是返回一个不透明的颜色,所以对操作颜色混合不是特别的有效;
基于以上说明和这个类已经过时,讲解到此结束;
引用:
Android Paint之 setXfermode PorterDuffXfermode 讲解 - Ajian_studio - 博客频道 - CSDN.NET
Android图像处理——Paint之Xfermode,androidxfermode_Android教程 | 帮客之家
8.3.4 Paint API之—— Xfermode与PorterDuff详解(一) | 菜鸟教程
详解Paint的setXfermode(Xfermode xfermode) - developer_Kale - 博客园