概述
类 Android.graphics.PorterDuffXfermode 继承自 android.graphics.Xfermode。
当绘图时和前面的图案有重叠部分,为了设置重叠规则,需要用到 PorterDuffXfermode,需要将将其作为参数传给 Paint.setXfermode(Xfermode xfermode) 方法。
PorterDuffXfermode 这个类中的 Porter 和 Duff 是两个人名,这两个人在 1984 年一起写了一篇名为《Compositing Digital Images》 的论文。
下面开始介绍 PorterDuffXfermode 的使用。
示例一
在演示 Xfermode 之前,先看一下下面的例子
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int r = canvas.getWidth() / 3;
// 设置背景色
canvas.drawARGB(255, 139, 197, 186);
//绘制黄色的圆形
paint.setColor(0xFFFFCC44);
canvas.drawCircle(r, r, r, paint);
//绘制蓝色的矩形
paint.setColor(0xFF66AAFF);
canvas.drawRect(r, r, r * 2.7f, r * 2.7f, paint);
}
重写了 View 的 onDraw 方法,首先将 View 的背景色设置为绿色,然后绘制了一个黄色的圆形,然后再绘制一个蓝色的矩形,效果如下所示:
没有设置 Xfermode 的时候,后来绘制的图形就会覆盖之前绘制的图形!
示例二
下面我们使用 Xfermode 对上面的代码进行一下修改,修改后的代码如下所示:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int r = canvas.getWidth() / 3;
// 设置背景色
canvas.drawARGB(255, 139, 197, 186);
//绘制黄色的圆形
paint.setColor(0xFFFFCC44);
canvas.drawCircle(r, r, r, paint);
//绘制蓝色的矩形
paint.setColor(0xFF66AAFF);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
canvas.drawRect(r, r, r * 2.7f, r * 2.7f, paint);
}
效果如下:
先来讲一下 setXfermode 的绘制原理:在 canvas.drawRect() 之前 setXfermode,那么所绘制的矩形中的像素称作源像素(source,简称 src),所绘制的矩形在 Canvas 中对应位置的矩形内的像素称作目标像素(destination,简称 dst)。根据 Xfermode 的规则,ARGB 的值会重新计算。
本例中 Xfermode 是 PorterDuff.Mode.CLEAR,直接将目标像素的 ARGB 四个分量全置为 0,即 (0,0,0,0),即透明色,所以实际上绘制了一个透明的矩形。但是效果图为什么是白色的呢,因为屏幕本身是白色的。
示例三
示例二中显示的白色,如果想要显示透明色,我们需要将代码作如下修改:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int r = canvas.getWidth() / 3;
// 设置背景色
canvas.drawARGB(255, 139, 197, 186);
int layerId = canvas.saveLayer(0, 0, canvas.getWidth(), canvas.getHeight(), null, Canvas.ALL_SAVE_FLAG);
//绘制黄色的圆形
paint.setColor(0xFFFFCC44);
canvas.drawCircle(r, r, r, paint);
//绘制蓝色的矩形
paint.setColor(0xFF66AAFF);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
canvas.drawRect(r, r, r * 2.7f, r * 2.7f, paint);
canvas.restoreToCount(layerId);
}
效果如下:
我们将绘制圆形与矩形的代码放到了 canvas.saveLayer() 和 canvas.restoreToCount() 之间。
关于 canvas 绘图中的 layer 有以下几点需要说明:
-
Canvas 是支持图层 layer 渲染这种技术的,Canvas 默认就有一个 layer,当我们平时调用 Canvas 的各种
drawXXX() 方法时,其实是把所有的东西都绘制到 Canvas 这个默认的 layer 上面。 -
我们还可以通过 canvas.saveLayer() 新建一个 layer,新建的 layer 放置在 canvas 默认 layer 的上部,当我们执行了 canvas.saveLayer() 之后,我们所有的绘制操作都绘制到了我们新建的 layer 上,而不是 canvas
默认的 layer。 -
用 canvas.saveLayer() 方法产生的 layer 所有像素的 ARGB 值都是 (0,0,0,0),即 canvas.saveLayer()
方法产生的 layer 初始时时完全透明的。 -
canvas.saveLayer() 方法会返回一个 int 值,用于表示 layer 的 ID,在我们对这个新 layer 绘制完成后可以通过调用 canvas.restoreToCount(layer) 或者 canvas.restore() 把这个 layer 绘制到 canvas 默认的 layer 上去,这样就完成了一个 layer 的绘制工作。
所以 CLEAR 操作时在新建的图层上面,背景色不再是 Activity 的背景色,变成了默认图层的背景色了。
一张被不经大脑疯传的神图
如果大家 Google 或百度 PorterDuffXfermode 相关的博文,大家肯定会看到下面这张神图,如下所示:
其实这张图有点问题,具体可以参照 http://blog.csdn.net/iispring/article/details/50472485
不同 Mode 的效果
PorterDuff.Mode.CLEAR, //清除
PorterDuff.Mode.SRC, //只绘制源图
PorterDuff.Mode.DST, //只绘制目标图像
PorterDuff.Mode.SRC_OVER, //在目标图像的上方绘制源图像
PorterDuff.Mode.DST_OVER, //在源图像的上方绘制目标图像
PorterDuff.Mode.SRC_IN, //只在源图像和目标图像相交的地方绘制源图像
PorterDuff.Mode.DST_IN, //只在源图像和目标图像相交的地方绘制目标图像
PorterDuff.Mode.SRC_OUT, //只在源图像和目标图像不相交的地方绘制源图像
PorterDuff.Mode.DST_OUT, //只在源图像和目标图像不相交的地方绘制目标图像
PorterDuff.Mode.SRC_ATOP, //在源图像和目标图像相交的地方绘制源图像,在不相交的地方绘制目标图像
PorterDuff.Mode.DST_ATOP, //在源图像和目标图像相交的地方绘制目标图像,在不相交的地方绘制源图像
PorterDuff.Mode.XOR, //在源图像和目标图像重叠之外的任何地方绘制他们,而在重叠的地方不绘制任何内容
PorterDuff.Mode.DARKEN, //变暗
PorterDuff.Mode.LIGHTEN, //变亮
PorterDuff.Mode.MULTIPLY, //正片叠底
PorterDuff.Mode.SCREEN, //滤色
PorterDuff.Mode.ADD, //饱和相加
PorterDuff.Mode.OVERLAY //叠加
代码可见 https://github.com/teletian/Android/tree/master/PorterDuffXfermode
网友评论