PorterDuffXferMode不正确的真正原因PorterDuffXferMode深入试验)
2016-10-13 18:28
411 查看
版权声明:本文为博主原创文章,欢迎注明出处后转载。
菜鸡wing遇敌PorterDuffXferMode,不料过于轻敌,应战吃力。随后与其大战三天三夜,三百余回合不分胜负。幸得
@咪咪控 相助,侥幸获胜。
关键字:PorterDuffXferMode 错误 不正确 不达到预期 bug
上一篇带来一个使用PorterDuffXferMode 做的 水波纹loadingview,中间遇到了点小困难。
(说人话) PorterDuffXferMode总是不能按照效果图预期的效果执行。关于PorterDuffXferMode的错误显示是一个对初学者十分深的坑,到底是bug呢,还是有需要注意的地方呢。这里就跟随我 带上手电筒,去一探究竟。
转载请注明出处:http://blog.csdn.NET/wingichoy/article/details/50534175
首先,大家都知道有一个图片:
![](https://oscdn.geek-share.com/Uploads/Images/Content/201911/05/097601d39660e54191ab6a179ba4a193)
然后,大部分时候 是看到了觉得很神奇,就跃跃欲试,尤其是src_in 和dstIn可以实现遮罩效果,例如圆角图片 圆形图片都用了这种模式。
于是就挨个测试各种模式是否生效,结果往往不能达到预期效果。我们来做个测试。
从最简单的开始:
1.直接在canvas上面绘制图形:
[java]
view plain
copy
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/9e12f1d3e499fc949c886e7c9e0484f9)
@Override
protected void onDraw(Canvas canvas) {
//dst
canvas.drawRect(20,20,80,80,mDstPaint);
//src
canvas.drawCircle(30,30,30,mSrcPaint);
}
原图效果是这样的:
![](https://oscdn.geek-share.com/Uploads/Images/Content/201911/05/8dbac7f318f352fa53d43cc494a26a3c)
现在加一个mode上来,XOR
[java]
view plain
copy
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/9e12f1d3e499fc949c886e7c9e0484f9)
@Override
protected void onDraw(Canvas canvas) {
//dst
canvas.drawRect(20,20,80,80,mDstPaint);
mSrcPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.XOR));
//src
canvas.drawCircle(30,30,30,mSrcPaint);
}
跑起来的结果是这样的:
![](https://oscdn.geek-share.com/Uploads/Images/Content/201911/05/be64ff3d480e3879229fca55c686ad6a)
WTF!!?? 这是什么鬼。不应该是相交部分消失吗。 网上说“硬件加速”对这个有影响,那么在构造器里关闭硬件加速试一下:
[java]
view plain
copy
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/9e12f1d3e499fc949c886e7c9e0484f9)
public TestView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mDstPaint = new Paint();
mSrcPaint = new Paint();
mDstPaint.setColor(Color.YELLOW);
mSrcPaint.setColor(Color.BLUE);
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
运行的结果:
![](https://oscdn.geek-share.com/Uploads/Images/Content/201911/05/e001f066bcf42e5a80b9682b1035e7a6)
这下正常了。相交的部分消失了。
结论1:硬件加速对PorterDuffXferMode有影响,使用前请关闭硬件加速。
那么这下真的天下太平了吗?nonono~不要太天真,不然怎么能叫万丈深渊呢。
继续试验其他模式: 将模式改为SRC_IN
![](https://oscdn.geek-share.com/Uploads/Images/Content/201911/05/488fba6e884597b0c7b90caa54065bde)
WTF?????跟效果图根本不一致好吗!!!! 在试试DST_IN
![](https://oscdn.geek-share.com/Uploads/Images/Content/201911/05/8d46f27cc4d7a267a5d9166d9364e8c1)
你确定你没有在逗我???? 怎么是这个鬼东西。 (当时鼓捣了我三天四夜,一直在日狗,不过先别急,慢慢来。)
为什么一定要按照那个效果图来呢。。。 因为特么的那个图是官方的一个demo。。 那么我们就来看看这个demo长什么样!
[java]
view plain
copy
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/9e12f1d3e499fc949c886e7c9e0484f9)
package io.appium.android.apis.graphics;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.Xfermode;
import android.os.Bundle;
import android.view.View;
public class Xfermodes extends GraphicsActivity {
// create a bitmap with a circle, used for the "dst" image
static 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;
}
// create a bitmap with a rect, used for the "src" image
static 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 onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new SampleView(this));
}
private static class SampleView extends View {
private static final int W = 64;
private static final int H = 64;
private static final int ROW_MAX = 4; // number of samples per row
private Bitmap mSrcB;
private Bitmap mDstB;
private Shader mBG; // background checker-board pattern
private static final Xfermode[] sModes = {
new PorterDuffXfermode(PorterDuff.Mode.CLEAR),
new PorterDuffXfermode(PorterDuff.Mode.SRC),
new PorterDuffXfermode(PorterDuff.Mode.DST),
new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER),
new PorterDuffXfermode(PorterDuff.Mode.DST_OVER),
new PorterDuffXfermode(PorterDuff.Mode.SRC_IN),
new PorterDuffXfermode(PorterDuff.Mode.DST_IN),
new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT),
new PorterDuffXfermode(PorterDuff.Mode.DST_OUT),
new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP),
new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP),
new PorterDuffXfermode(PorterDuff.Mode.XOR),
new PorterDuffXfermode(PorterDuff.Mode.DARKEN),
new PorterDuffXfermode(PorterDuff.Mode.LIGHTEN),
new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY),
new PorterDuffXfermode(PorterDuff.Mode.SCREEN)
};
private static final String[] sLabels = {
"Clear", "Src", "Dst", "SrcOver",
"DstOver", "SrcIn", "DstIn", "SrcOut",
"DstOut", "SrcATop", "DstATop", "Xor",
"Darken", "Lighten", "Multiply", "Screen"
};
public SampleView(Context context) {
super(context);
mSrcB = makeSrc(W, H);
mDstB = makeDst(W, H);
// make a ckeckerboard pattern
Bitmap bm = Bitmap.createBitmap(new int[] { 0xFFFFFFFF, 0xFFCCCCCC,
0xFFCCCCCC, 0xFFFFFFFF }, 2, 2,
Bitmap.Config.RGB_565);
mBG = new BitmapShader(bm,
Shader.TileMode.REPEAT,
Shader.TileMode.REPEAT);
Matrix m = new Matrix();
m.setScale(6, 6);
mBG.setLocalMatrix(m);
}
@Override protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.WHITE);
Paint labelP = new Paint(Paint.ANTI_ALIAS_FLAG);
labelP.setTextAlign(Paint.Align.CENTER);
Paint paint = new Paint();
paint.setFilterBitmap(false);
canvas.translate(15, 35);
int x = 0;
int y = 0;
for (int i = 0; i < sModes.length; i++) {
// draw the border
paint.setStyle(Paint.Style.STROKE);
paint.setShader(null);
canvas.drawRect(x - 0.5f, y - 0.5f,
x + W + 0.5f, y + H + 0.5f, paint);
// draw the checker-board pattern
paint.setStyle(Paint.Style.FILL);
paint.setShader(mBG);
canvas.drawRect(x, y, x + W, y + H, paint);
// draw the src/dst example into our offscreen bitmap
int sc = canvas.saveLayer(x, y, x + W, y + H, 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);
canvas.translate(x, y);
canvas.drawBitmap(mDstB, 0, 0, paint);
paint.setXfermode(sModes[i]);
canvas.drawBitmap(mSrcB, 0, 0, paint);
paint.setXfermode(null);
canvas.restoreToCount(sc);
// draw the label
canvas.drawText(sLabels[i],
x + W/2, y - labelP.getTextSize()/2, labelP);
x += W + 10;
// wrap around when we've drawn enough for one row
if ((i % ROW_MAX) == ROW_MAX - 1) {
x = 0;
y += H + 30;
}
}
}
}
}
一点一点看,截取onDraw里面的片段,这里
[java]
view plain
copy
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/9e12f1d3e499fc949c886e7c9e0484f9)
canvas.drawBitmap(mDstB, 0, 0, paint);
paint.setXfermode(sModes[i]);
canvas.drawBitmap(mSrcB, 0, 0, paint);
paint.setXfermode(null);
他是画了两个bitmap。网上有人说好像只对bitmap生效,那到底是不是这样呢。我们来试验一下。
我们新定义一个canvas 再定义一个bitmap 现在bitmap上画出来src 然后将bitmap画到canvas上:
[java]
view plain
copy
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/9e12f1d3e499fc949c886e7c9e0484f9)
public TestView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mDstPaint = new Paint();
mSrcPaint = new Paint();
mDstPaint.setColor(Color.YELLOW);
mSrcPaint.setColor(Color.BLUE);
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
mSrcBitmap = Bitmap.createBitmap(50,50, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mSrcBitmap);
}
[java]
view plain
copy
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/9e12f1d3e499fc949c886e7c9e0484f9)
@Override
protected void onDraw(Canvas canvas) {
//dst
canvas.drawRect(20,20,80,80,mDstPaint);
//src
/ mSrcPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
mCanvas.drawCircle(25,25,25,mSrcPaint);
canvas.drawBitmap(mSrcBitmap,0,0,null);
}
现在的效果是这样的:
![](https://oscdn.geek-share.com/Uploads/Images/Content/201911/05/acc32ff8271d83422a82439fc5fb1dc8)
加一个XOR 试试。。
日了狗了!!!!!没反应啊,到底是什么鬼。
![](https://oscdn.geek-share.com/Uploads/Images/Content/201911/05/6f4131af8a9d0b444ea84051e8aed9e4)
是不是两个都需要bitmap才可以呢,再创建一个dstBitmap和dstCanvas?
[java]
view plain
copy
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/9e12f1d3e499fc949c886e7c9e0484f9)
mDstBitmap = Bitmap.createBitmap(50,50, Bitmap.Config.ARGB_8888);
mDstCanvas = new Canvas(mDstBitmap);
加一个XOR 试试
[java]
view plain
copy
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/9e12f1d3e499fc949c886e7c9e0484f9)
@Override
protected void onDraw(Canvas canvas) {
//dst
mDstCanvas.drawRect(20,20,80,80,mDstPaint);
canvas.drawBitmap(mDstBitmap,0,0,mDstPaint);
//src
mSrcPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.XOR));
mSrcCanvas.drawCircle(25,25,25,mSrcPaint);
canvas.drawBitmap(mSrcBitmap,0,0,mSrcPaint);
}
效果如下:
![](https://oscdn.geek-share.com/Uploads/Images/Content/201911/05/fb50671f0297dbfd045b979ab2ec2cf2)
终于他妈的出来了!!!!那其他效果呢?
clear
![](https://oscdn.geek-share.com/Uploads/Images/Content/201911/05/b7a9be39b56d8657d7c9cdbd846d9a08)
一致的!!!!好激动有没有!!!!搞了4天 越来越接近结论了!!!
结论2:只有两个bitmap的时候,才可以生效。
不要高兴太早。。如果坑到这里就完了,那还叫坑么。
继续试。。嗯 好多模式都是一致的。
直到!!!SRC_IN和DST_IN ,会发现。。。都消失了。 为毛呢??
检查代码 发现 在往bitmap画圆之前就set了mode 这样会有影响
纠正
[java]
view plain
copy
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/9e12f1d3e499fc949c886e7c9e0484f9)
@Override
protected void onDraw(Canvas canvas) {
//dst
mDstCanvas.drawRect(20,20,80,80,mDstPaint);
canvas.drawBitmap(mDstBitmap,0,0,mDstPaint);
//src
mSrcCanvas.drawCircle(25,25,25,mSrcPaint);
//再画圆之后 设置mode
mSrcPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.XOR));
canvas.drawBitmap(mSrcBitmap,0,0,mSrcPaint);
}
发现
![](https://oscdn.geek-share.com/Uploads/Images/Content/201911/05/083a460bf38488c6b35315c5099f1bb9)
艹!!!!!!终于好了!!!!!!!!经过不懈努力!!!撒花!*★,°*:.☆\( ̄▽ ̄)/$:*.°★* 。
其实我们刚才bitmap的大小是一样的。 然后都是从0,0开始 完全覆盖了。
那么错开一点点 是什么效果呢,调整代码如下
[java]
view plain
copy
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/9e12f1d3e499fc949c886e7c9e0484f9)
protected void onDraw(Canvas canvas) {
//dst
mDstCanvas.drawRect(20,20,80,80,mDstPaint);
canvas.drawBitmap(mDstBitmap,20,20,mDstPaint);
//src
mSrcCanvas.drawCircle(25,25,25,mSrcPaint);
mSrcPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(mSrcBitmap,0,0,mSrcPaint);
}
效果如下:
![](https://oscdn.geek-share.com/Uploads/Images/Content/201911/05/fb7a6cf9993b40f225a014efadb6a490)
可以看有效果了!!!! 但是是一个什么鬼!!! 矩形缺角??加蓝色一点??
这样看是很难看出效果的。。来调整一下bitmap的底色 和矩形的大小:
把两个bitmap的底色都画成灰色, 矩形不要占满画布 留出空间
[java]
view plain
copy
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/9e12f1d3e499fc949c886e7c9e0484f9)
mDstCanvas.drawColor(Color.GRAY);
[java]
view plain
copy
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/9e12f1d3e499fc949c886e7c9e0484f9)
@Override
protected void onDraw(Canvas canvas) {
//dst 黄色
mDstCanvas.drawRect(0,0,40,40,mDstPaint);
canvas.drawBitmap(mDstBitmap,20,20,mDstPaint);
//src 蓝色
mSrcCanvas.drawCircle(25,25,25,mSrcPaint);
canvas.drawBitmap(mSrcBitmap,0,0,mSrcPaint);
}
效果如下。。 嗯 这样就是两个bitmap了。。很明了 bitmap的内容 位置,
![](https://oscdn.geek-share.com/Uploads/Images/Content/201911/05/13fa2d951d93c0a573f6c0ede7d1b718)
然后再搞SRC_IN模式
![](https://oscdn.geek-share.com/Uploads/Images/Content/201911/05/a4a40ec02c089421deb2ecad93ba9342)
dst_in
![](https://oscdn.geek-share.com/Uploads/Images/Content/201911/05/db1c495f4cc134cfbb92a42dc242741c)
那么把bitmap底色去掉。 改成透明的呢?
dst_in:
![](https://oscdn.geek-share.com/Uploads/Images/Content/201911/05/74f5274d686d33046c7e0ae2c5bfdc2b)
SRC_IN:
![](https://oscdn.geek-share.com/Uploads/Images/Content/201911/05/be0d72b9e7ad00b828725e7ea7ece62a)
总结3:两个bitmap位置不完全重叠的效果如上,并不能总结出效果,要按实际效果来。
---------------------------------------------------------------------------------------------------------华丽丽的分割线-----------------------------------------------------------------------------------------
最终大总结,如果想让PorterDuffXferMode按照预期Demo(或者效果图)的效果图像实现,必须满足以下条件:
1、关闭硬件加速。
2、两个bitmap大小尽量一样。
3、背景色为透明色。
4、如果两个bitmap位置不完全一样,可能也是预期效果,只不过你看到的效果和你自己脑补的预期效果不一致。
最后想再说几句。鼓捣这个模式鼓捣了几乎一周,每天晚上下班都在搞。查了无数资料。但是好多不完整,甚至有一些误导性。所以为了避免后来者入坑。亲自试验,尽量总结。 如果有说的不正确的地方请及时向我提出。我会及时改正。
如果本文帮助到了你,请点一个顶,或者评论一下,蟹蟹!!!!
菜鸡wing遇敌PorterDuffXferMode,不料过于轻敌,应战吃力。随后与其大战三天三夜,三百余回合不分胜负。幸得
@咪咪控 相助,侥幸获胜。
关键字:PorterDuffXferMode 错误 不正确 不达到预期 bug
上一篇带来一个使用PorterDuffXferMode 做的 水波纹loadingview,中间遇到了点小困难。
(说人话) PorterDuffXferMode总是不能按照效果图预期的效果执行。关于PorterDuffXferMode的错误显示是一个对初学者十分深的坑,到底是bug呢,还是有需要注意的地方呢。这里就跟随我 带上手电筒,去一探究竟。
转载请注明出处:http://blog.csdn.NET/wingichoy/article/details/50534175
首先,大家都知道有一个图片:
然后,大部分时候 是看到了觉得很神奇,就跃跃欲试,尤其是src_in 和dstIn可以实现遮罩效果,例如圆角图片 圆形图片都用了这种模式。
于是就挨个测试各种模式是否生效,结果往往不能达到预期效果。我们来做个测试。
从最简单的开始:
1.直接在canvas上面绘制图形:
[java]
view plain
copy
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
@Override
protected void onDraw(Canvas canvas) {
//dst
canvas.drawRect(20,20,80,80,mDstPaint);
//src
canvas.drawCircle(30,30,30,mSrcPaint);
}
原图效果是这样的:
现在加一个mode上来,XOR
[java]
view plain
copy
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
@Override
protected void onDraw(Canvas canvas) {
//dst
canvas.drawRect(20,20,80,80,mDstPaint);
mSrcPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.XOR));
//src
canvas.drawCircle(30,30,30,mSrcPaint);
}
跑起来的结果是这样的:
WTF!!?? 这是什么鬼。不应该是相交部分消失吗。 网上说“硬件加速”对这个有影响,那么在构造器里关闭硬件加速试一下:
[java]
view plain
copy
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
public TestView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mDstPaint = new Paint();
mSrcPaint = new Paint();
mDstPaint.setColor(Color.YELLOW);
mSrcPaint.setColor(Color.BLUE);
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
运行的结果:
这下正常了。相交的部分消失了。
结论1:硬件加速对PorterDuffXferMode有影响,使用前请关闭硬件加速。
那么这下真的天下太平了吗?nonono~不要太天真,不然怎么能叫万丈深渊呢。
继续试验其他模式: 将模式改为SRC_IN
WTF?????跟效果图根本不一致好吗!!!! 在试试DST_IN
你确定你没有在逗我???? 怎么是这个鬼东西。 (当时鼓捣了我三天四夜,一直在日狗,不过先别急,慢慢来。)
为什么一定要按照那个效果图来呢。。。 因为特么的那个图是官方的一个demo。。 那么我们就来看看这个demo长什么样!
[java]
view plain
copy
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
package io.appium.android.apis.graphics;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.Xfermode;
import android.os.Bundle;
import android.view.View;
public class Xfermodes extends GraphicsActivity {
// create a bitmap with a circle, used for the "dst" image
static 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;
}
// create a bitmap with a rect, used for the "src" image
static 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 onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new SampleView(this));
}
private static class SampleView extends View {
private static final int W = 64;
private static final int H = 64;
private static final int ROW_MAX = 4; // number of samples per row
private Bitmap mSrcB;
private Bitmap mDstB;
private Shader mBG; // background checker-board pattern
private static final Xfermode[] sModes = {
new PorterDuffXfermode(PorterDuff.Mode.CLEAR),
new PorterDuffXfermode(PorterDuff.Mode.SRC),
new PorterDuffXfermode(PorterDuff.Mode.DST),
new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER),
new PorterDuffXfermode(PorterDuff.Mode.DST_OVER),
new PorterDuffXfermode(PorterDuff.Mode.SRC_IN),
new PorterDuffXfermode(PorterDuff.Mode.DST_IN),
new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT),
new PorterDuffXfermode(PorterDuff.Mode.DST_OUT),
new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP),
new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP),
new PorterDuffXfermode(PorterDuff.Mode.XOR),
new PorterDuffXfermode(PorterDuff.Mode.DARKEN),
new PorterDuffXfermode(PorterDuff.Mode.LIGHTEN),
new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY),
new PorterDuffXfermode(PorterDuff.Mode.SCREEN)
};
private static final String[] sLabels = {
"Clear", "Src", "Dst", "SrcOver",
"DstOver", "SrcIn", "DstIn", "SrcOut",
"DstOut", "SrcATop", "DstATop", "Xor",
"Darken", "Lighten", "Multiply", "Screen"
};
public SampleView(Context context) {
super(context);
mSrcB = makeSrc(W, H);
mDstB = makeDst(W, H);
// make a ckeckerboard pattern
Bitmap bm = Bitmap.createBitmap(new int[] { 0xFFFFFFFF, 0xFFCCCCCC,
0xFFCCCCCC, 0xFFFFFFFF }, 2, 2,
Bitmap.Config.RGB_565);
mBG = new BitmapShader(bm,
Shader.TileMode.REPEAT,
Shader.TileMode.REPEAT);
Matrix m = new Matrix();
m.setScale(6, 6);
mBG.setLocalMatrix(m);
}
@Override protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.WHITE);
Paint labelP = new Paint(Paint.ANTI_ALIAS_FLAG);
labelP.setTextAlign(Paint.Align.CENTER);
Paint paint = new Paint();
paint.setFilterBitmap(false);
canvas.translate(15, 35);
int x = 0;
int y = 0;
for (int i = 0; i < sModes.length; i++) {
// draw the border
paint.setStyle(Paint.Style.STROKE);
paint.setShader(null);
canvas.drawRect(x - 0.5f, y - 0.5f,
x + W + 0.5f, y + H + 0.5f, paint);
// draw the checker-board pattern
paint.setStyle(Paint.Style.FILL);
paint.setShader(mBG);
canvas.drawRect(x, y, x + W, y + H, paint);
// draw the src/dst example into our offscreen bitmap
int sc = canvas.saveLayer(x, y, x + W, y + H, 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);
canvas.translate(x, y);
canvas.drawBitmap(mDstB, 0, 0, paint);
paint.setXfermode(sModes[i]);
canvas.drawBitmap(mSrcB, 0, 0, paint);
paint.setXfermode(null);
canvas.restoreToCount(sc);
// draw the label
canvas.drawText(sLabels[i],
x + W/2, y - labelP.getTextSize()/2, labelP);
x += W + 10;
// wrap around when we've drawn enough for one row
if ((i % ROW_MAX) == ROW_MAX - 1) {
x = 0;
y += H + 30;
}
}
}
}
}
一点一点看,截取onDraw里面的片段,这里
[java]
view plain
copy
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
canvas.drawBitmap(mDstB, 0, 0, paint);
paint.setXfermode(sModes[i]);
canvas.drawBitmap(mSrcB, 0, 0, paint);
paint.setXfermode(null);
他是画了两个bitmap。网上有人说好像只对bitmap生效,那到底是不是这样呢。我们来试验一下。
我们新定义一个canvas 再定义一个bitmap 现在bitmap上画出来src 然后将bitmap画到canvas上:
[java]
view plain
copy
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
public TestView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mDstPaint = new Paint();
mSrcPaint = new Paint();
mDstPaint.setColor(Color.YELLOW);
mSrcPaint.setColor(Color.BLUE);
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
mSrcBitmap = Bitmap.createBitmap(50,50, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mSrcBitmap);
}
[java]
view plain
copy
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
@Override
protected void onDraw(Canvas canvas) {
//dst
canvas.drawRect(20,20,80,80,mDstPaint);
//src
/ mSrcPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
mCanvas.drawCircle(25,25,25,mSrcPaint);
canvas.drawBitmap(mSrcBitmap,0,0,null);
}
现在的效果是这样的:
加一个XOR 试试。。
日了狗了!!!!!没反应啊,到底是什么鬼。
是不是两个都需要bitmap才可以呢,再创建一个dstBitmap和dstCanvas?
[java]
view plain
copy
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
mDstBitmap = Bitmap.createBitmap(50,50, Bitmap.Config.ARGB_8888);
mDstCanvas = new Canvas(mDstBitmap);
加一个XOR 试试
[java]
view plain
copy
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
@Override
protected void onDraw(Canvas canvas) {
//dst
mDstCanvas.drawRect(20,20,80,80,mDstPaint);
canvas.drawBitmap(mDstBitmap,0,0,mDstPaint);
//src
mSrcPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.XOR));
mSrcCanvas.drawCircle(25,25,25,mSrcPaint);
canvas.drawBitmap(mSrcBitmap,0,0,mSrcPaint);
}
效果如下:
终于他妈的出来了!!!!那其他效果呢?
clear
一致的!!!!好激动有没有!!!!搞了4天 越来越接近结论了!!!
结论2:只有两个bitmap的时候,才可以生效。
不要高兴太早。。如果坑到这里就完了,那还叫坑么。
继续试。。嗯 好多模式都是一致的。
直到!!!SRC_IN和DST_IN ,会发现。。。都消失了。 为毛呢??
检查代码 发现 在往bitmap画圆之前就set了mode 这样会有影响
纠正
[java]
view plain
copy
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
@Override
protected void onDraw(Canvas canvas) {
//dst
mDstCanvas.drawRect(20,20,80,80,mDstPaint);
canvas.drawBitmap(mDstBitmap,0,0,mDstPaint);
//src
mSrcCanvas.drawCircle(25,25,25,mSrcPaint);
//再画圆之后 设置mode
mSrcPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.XOR));
canvas.drawBitmap(mSrcBitmap,0,0,mSrcPaint);
}
发现
艹!!!!!!终于好了!!!!!!!!经过不懈努力!!!撒花!*★,°*:.☆\( ̄▽ ̄)/$:*.°★* 。
其实我们刚才bitmap的大小是一样的。 然后都是从0,0开始 完全覆盖了。
那么错开一点点 是什么效果呢,调整代码如下
[java]
view plain
copy
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
protected void onDraw(Canvas canvas) {
//dst
mDstCanvas.drawRect(20,20,80,80,mDstPaint);
canvas.drawBitmap(mDstBitmap,20,20,mDstPaint);
//src
mSrcCanvas.drawCircle(25,25,25,mSrcPaint);
mSrcPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(mSrcBitmap,0,0,mSrcPaint);
}
效果如下:
可以看有效果了!!!! 但是是一个什么鬼!!! 矩形缺角??加蓝色一点??
这样看是很难看出效果的。。来调整一下bitmap的底色 和矩形的大小:
把两个bitmap的底色都画成灰色, 矩形不要占满画布 留出空间
[java]
view plain
copy
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
mDstCanvas.drawColor(Color.GRAY);
[java]
view plain
copy
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
@Override
protected void onDraw(Canvas canvas) {
//dst 黄色
mDstCanvas.drawRect(0,0,40,40,mDstPaint);
canvas.drawBitmap(mDstBitmap,20,20,mDstPaint);
//src 蓝色
mSrcCanvas.drawCircle(25,25,25,mSrcPaint);
canvas.drawBitmap(mSrcBitmap,0,0,mSrcPaint);
}
效果如下。。 嗯 这样就是两个bitmap了。。很明了 bitmap的内容 位置,
然后再搞SRC_IN模式
dst_in
那么把bitmap底色去掉。 改成透明的呢?
dst_in:
SRC_IN:
总结3:两个bitmap位置不完全重叠的效果如上,并不能总结出效果,要按实际效果来。
---------------------------------------------------------------------------------------------------------华丽丽的分割线-----------------------------------------------------------------------------------------
最终大总结,如果想让PorterDuffXferMode按照预期Demo(或者效果图)的效果图像实现,必须满足以下条件:
1、关闭硬件加速。
2、两个bitmap大小尽量一样。
3、背景色为透明色。
4、如果两个bitmap位置不完全一样,可能也是预期效果,只不过你看到的效果和你自己脑补的预期效果不一致。
最后想再说几句。鼓捣这个模式鼓捣了几乎一周,每天晚上下班都在搞。查了无数资料。但是好多不完整,甚至有一些误导性。所以为了避免后来者入坑。亲自试验,尽量总结。 如果有说的不正确的地方请及时向我提出。我会及时改正。
如果本文帮助到了你,请点一个顶,或者评论一下,蟹蟹!!!!
相关文章推荐
- PorterDuffXferMode不正确的真正原因PorterDuffXferMode深入试验)
- PorterDuffXferMode不正确的真正原因PorterDuffXferMode深入试验)
- PorterDuffXferMode不正确的真正原因PorterDuffXferMode深入试验)
- PorterDuffXferMode不正确的真正原因PorterDuffXferMode深入试验
- 细数PorterDuffXferMode的几个坑, PorterDuffXferMode不正确的真正原因
- PorterDuffXferMode不正确的真正原因PorterDuffXferMode深入试验)
- PorterDuffXferMode不正确的真正原因PorterDuffXferMode深入试验)
- PorterDuffXferMode不对的真正原因PorterDuffXferMode深入试验)
- PorterDuffXfermode 正确使用方式(详解)
- PorterDuffXfermode合成圆形图片显示不正确
- PorterDuffXfermode学习
- Android中Canvas绘图之PorterDuffXfermode使用
- Canvas的drawBitmap以及Paint的PorterDuffXfermode使用心得
- 初学PorterDuffXfermode(实现刮刮乐)
- PorterDuffXfermode
- Android基础入门教程——8.3.5 Paint API之—— Xfermode与PorterDuff详解(二)
- 自定义控件(6)---PorterDuffXfermode图形过滤器之橡皮擦应用
- Paint PorterDuff及Xfermode详解
- Paint---PorterDuffXfermode
- Paint画笔特效之PorterDuffXfermode