官方介绍:
Xfermode是被用来在绘图管道中实现自定义“传输模式”的对象的基类,可以通过调用子类的构造函数且传入Mode(混合模式,下面会说到)
这个类只有一个基类,可能有哥们说:不对,我看的是三个子类;好!官方API让你死心:
其他2个类早被移除了!所以接下来我们说说PorterDuffXfermode这个类。
PorterDuffXfermode:
专门实现Paint的传输模式。有关可用的alpha合成和混合模式的更多信息,请参阅PorterDuff.Mode枚举的文档
这个类的结构很简单,只有一个带有枚举参数的构造方法:
public class PorterDuffXfermode extends Xfermode {
/**
* Create an xfermode that uses the specified porter-duff mode.
*
* @param mode The porter-duff mode that is applied
*/
public PorterDuffXfermode(PorterDuff.Mode mode) {
porterDuffMode = mode.nativeInt;
}
}
所以我们的重点就是去了解构造函数中的枚举模式,我们先看下PorterDuff.Mode:
Porter-Duff:
这个类的名字是对托马斯·波特(Thomas Porter)和汤姆·达夫(Tom Duff)贡献的敬意,也就是这两个人姓氏作为该类的命名,在他们1984年发表的题为“合成数字图像”,在这篇文章中,作者描述了12个合成算法,这些算法管理如何把源图像绘制到目标图像以及呈现的颜色。
“合成数字图像”于1984年7月在Computer Graphics第18卷第3号上发表。
因为波特和达夫的工作仅仅关注源图像和目标图像的alpha通道的影响,原始文件中描述的12个算法在这里被称为alpha合成模式。
这个类还提供了几种混合模式,它们类似地定义了源图像和目标图像的结果,但没有被限制到alpha通道。 这些混合模式不是Porter和Duff定义的,但是为了方便起见,已经包含在这个类中。
以上是来自官网的翻译和个人对Xfermode相关类的理解,若有错误,请指出,不胜感激!
PorterDuff.Mode:
上面,我们提到了PorterDuff.Mode枚举分为两种, alpha合成模式和混合模式,有兴趣的可以去看官网:PorterDuff.Mode(自备梯子),我建议大家最好去自己实现以下这18种模式,这样有利于我们加深理解,我们看下有哪18种模式呢:
public enum Mode {
CLEAR (0),
SRC (1),
DST (2),
SRC_OVER (3),
DST_OVER (4),
SRC_IN (5),
DST_IN (6),
SRC_OUT (7),
DST_OUT (8),
SRC_ATOP (9),
DST_ATOP (10),
XOR (11),
DARKEN (16),
LIGHTEN (17),
MULTIPLY (13),
SCREEN (14),
ADD (12),
OVERLAY (15);
下面我们挨个去绘制出以上18种模式效果:
注意:在开始绘制前,需要关闭硬件加速,因为有的模式不支持硬件加速,而硬件加速默认开启,你可以在清单文件中关掉:
<Application android:hardwareAccelerated="false"/>
或则在自定义view中:
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
你可以尝试下,CLEAR模式下,不关闭硬件加速就不会显示正常效果。
我们按照官网标准(这里是官方截图):
分别绘制一张蓝色矩形的源图像、一张红色圆形的目标图像,先绘制目标图像,再绘制源图像,也就是说先绘制红色圆形图像,再绘制蓝色矩形图像,背景是灰色。
SRC模式:
说明:只显示源图
CLEAR模式:
说明:都未显示,灰色是背景
DST模式:
说明:只显示目标图
SRC_OVER模式:
说明:源图绘制在目标图的上层
DST_OVER模式:
说明:目标图绘制在源图的上层
SRC_IN模式:
说明:显示目标图与源图的交集,且只显示源图部分
DST_IN模式:
说明:显示目标图与源图的交集,且只显示目标图部分
SRC_OUT模式:
说明:保留不包括目标图的源图
DST_OUT模式:
说明:保留未被源图覆盖的目标图
SRC_ATOP模式:
说明:丢弃不包含的源图
DST_ATOP模式:
说明:丢弃未被源图覆盖的目标图
XOR模式:
说明:去除源图和目标图的交集
DARKEN模式:
说明:保留源像素和目标像素,且交集颜色改变
LIGHTEN模式:
说明:保留源图和目标图,且交集颜色改变
MULTIPLY模式:
说明:将源像素和目标像素相乘<官方>
SCREEN模式:
说明:添加源像素和目标像素,然后减去乘以目标的源像素<官方>
ADD模式:
说明:将源像素添加到目标像素并使结果饱和<官方>
OVERLAY模式:
说明:取决于目标颜色,将源和目标相乘或屏蔽<官方>
以上就是18种模式混合后的效果,下面贴下实现的代码:
public class PorterDuffModeView extends View {
Paint paint;
public PorterDuffModeView(Context context) {
// super(context);
this(context, null);
}
public PorterDuffModeView(Context context, @Nullable AttributeSet attrs) {
// super(context, attrs);
this(context, attrs, 0);
paint = new Paint();
//几种混合规则在GPU硬件加速下不起效,如果你觉得混合模式没有正确使用,
// 可以让调用View.setLayerType(View.LAYER_TYPE_SOFTWARE, null)方法
// setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
public PorterDuffModeView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//离屏缓存
canvas.drawColor(Color.GRAY);
int sc= canvas.saveLayer(0f, 0f, getWidth(), getHeight(), null, Canvas.ALL_SAVE_FLAG);
canvas.drawBitmap(getBitmapDest(getWidth(),getHeight()), 0, 0, paint);
//这里设置模式,共18种
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.OVERLAY));
canvas.drawBitmap(getBitmapSrc(getWidth(),getHeight()), 0, 0, paint);
// 还原混合模式
paint.setXfermode(null);
// 还原画布
canvas.restoreToCount(sc);
}
/**
* 目标图像 红色圆
* @param width
* @param height
* @return
*/
public static Bitmap getBitmapDest(int width, int height) {
Bitmap bitmap = Bitmap.createBitmap(width, height,
Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.parseColor("#E91E63"));
canvas.drawCircle(width/2 , height / 2, Math.min(width / 4, height / 4), paint);
return bitmap;
}
/**
* 目标图像 蓝色矩形
* @param width
* @param height
* @return
*/
public static Bitmap getBitmapSrc(int width, int height) {
Bitmap bitmap = Bitmap.createBitmap(width, height,
Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.parseColor("#2196F3"));
canvas.drawRect(new RectF(0,0.5f*height,0.5f*width,height),paint);
return bitmap;
}
}
代码在github,可以clone看下效果!