菜鸡wing遇敌PorterDuffXferMode,不料过于轻敌,应战吃力。随后与其大战三天三夜,三百余回合不分胜负。幸得 @咪咪控 相助,侥幸获胜。

关键字:PorterDuffXferMode  错误 不正确  不达到预期  bug

上一篇带来一个使用PorterDuffXferMode  做的 水波纹loadingview,中间遇到了点小困难。

(说人话)  PorterDuffXferMode总是不能按照效果图预期的效果执行。关于PorterDuffXferMode的错误显示是一个对初学者十分深的坑,到底是bug呢,还是有需要注意的地方呢。这里就跟随我 带上手电筒,去一探究竟。

转载请注明出处:http://blog.csdn.net/wingichoy/article/details/50534175

首先,大家都知道有一个图片:

然后,大部分时候 是看到了觉得很神奇,就跃跃欲试,尤其是src_in  和dstIn可以实现遮罩效果,例如圆角图片 圆形图片都用了这种模式。

于是就挨个测试各种模式是否生效,结果往往不能达到预期效果。我们来做个测试。

从最简单的开始:

1.直接在canvas上面绘制图形

  @Override
protected void onDraw(Canvas canvas) {
//dst
canvas.drawRect(20,20,80,80,mDstPaint); //src
canvas.drawCircle(30,30,30,mSrcPaint); }

原图效果是这样的:

现在加一个mode上来,XOR

    @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!!?? 这是什么鬼。不应该是相交部分消失吗。 网上说“硬件加速”对这个有影响,那么在构造器里关闭硬件加速试一下:

 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长什么样!

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里面的片段,这里

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上:

 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);
}

 @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?

        mDstBitmap =  Bitmap.createBitmap(50,50, Bitmap.Config.ARGB_8888);
mDstCanvas = new Canvas(mDstBitmap);

加一个XOR 试试

 @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  这样会有影响

纠正

 @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开始 完全覆盖了。

那么错开一点点 是什么效果呢,调整代码如下

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的底色都画成灰色, 矩形不要占满画布 留出空间

mDstCanvas.drawColor(Color.GRAY);

  @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深入试验)的更多相关文章

  1. C#调用dll提示"试图加载格式不正确的程序"原因及解决方法

    转载:https://blog.csdn.net/songyi160/article/details/51354660 程序在32位操作系统上运行正常,在64位操作系统上运行读卡功能提示”试图加载格式 ...

  2. PorterDuffXferMode不对的真正原因PorterDuffXferMode深入试验)

    菜鸡wing遇敌PorterDuffXferMode,不料过于轻敌,应战吃力. 随后与其大战三天三夜.三百余回合不分胜负. 幸得 @咪咪控 相助,侥幸获胜. keyword:PorterDuffXfe ...

  3. 关于js中 document.body.scrollTop 不能返回正确值的原因

    本来是为了通过document.body.scrollTop来获取浏览器垂直滚动条向下滚动的像素,但是不管滚动条在什么位置总是返回是0,造成这样的原因和html的头部声明有关,如果头部声明 为:< ...

  4. modelsim仿真正确FPGA运行不正确的可能原因 - cm4写寄存器错

    困住整整一周了,工作进行不下去,中午偶遇导师,指导意见是有两种可能: 1.  FPGA编译器优化代码,可以考虑把综合过程中所有的warning排查一下 2.  verilog里有不可综合的语句. 又及 ...

  5. 十分钟搞定微信企业帐号“echostr校验失败,请您检查是否正确解密并输出明文echostr”

    问题域:在这里我们只解决密文可以正确解密,但微信验证提示“echostr校验失败,请您检查是否正确解密并输出明文echostr”的问题. 干货:没有正确验证的原因是:你给微信返回的是字符串,而微信需要 ...

  6. oracle 未找到提供程序。该程序可能未正确安装

    使用ADO连接oracle数据库时,连接串使用Provider=OraOLEDB.Oracle时提示"未找到提供程序.该程序可能未正确安装". 原因:由于我之间安装oracle_o ...

  7. SQLite 解决:Could not load file or assembly 'System.Data.SQLite ... 试图加载格式不正确的程序/or one of its dependencies. 找不到指定的模块。

     Could not load file or assembly 'System.Data.SQLite.dll' or one of its dependencies. 找不到指定的模块. 错误提示 ...

  8. web站点,同一个浏览器只能登陆一个用户的原因(cookie不能跨浏览器)

    我的web站点,比如  http://ip/testsite/default.aspx, 当我在我的机器上,用chrome打开,用账号user1登陆,那么当我再新开个tab,再打开这个web站点,这时 ...

  9. C# 遇到的报错:1、试图加载格式不正确、2、线程间操作无效

    一. 调用第三方控件出现“试图加载格式不正确的程序”原因与解决办法 二. 线程间操作无效: 从不是创建控件"Form1"的线程访问它. 1) C#中Invoke的用法

随机推荐

  1. 分别用face++和百度获取人脸属性(python单机版)

    称之为单机版,主要是相对于调用摄像头实时识别而言.本篇主要py2下利用face++和百度接口获取本地图片中的人脸属性,并按照一定格式保存数据. face++版 face++是刚注册的,只能用一个试用的 ...

  2. AJAX编程实践

    ---------------------------------------------------------------------------------------------------- ...

  3. 【Unity Shader】新书封面 — Low Polygon风格的渲染

    写在前面 最近又开心又担心,因为我的书马上就要上市了,开心当然是因为等了这么久终于可以如愿了,担心是因为不少人对它的期待都很大,我第一次写书,能力也有限,不知道能不能让大家满意,让大家也都喜欢上它.不 ...

  4. Java基本语法-----java数据类型的转换

    前言 Java中可以进行不同数据类型的加减乘除运算吗?是可以的.在算术运算符中已经体验过如果两个整数(int)相除会去掉小数部分.如果需要保留小数部分,可以让除数或者被除数变为double类型的(5变 ...

  5. 看见的力量 – (I) 解题的思维

    本文转自台湾李智桦老师的博客,原文地址 这篇文章:已经梗了我三个多星期了.这期间飞了二次大陆做演讲.往返几个大城市做教授敏捷开发运用在精实创业的课程.教材内容都是简体的,它们始终没有机会在国内用上,心 ...

  6. 【Android 系统开发】使用 Source InSight 阅读 Android 源码

    1. 安装 Source Insight (1) Source Insight 相关资源 安装相关资源 : -- 下载地址 : http://www.sourceinsight.com/down35. ...

  7. Android核心安全机制(一)

    Android六种核心安全机制-加密.密钥.签名与证书 对于移动开发,程序猿很容易会忘记一些安全问题,如一个MD5的加密,大部分人都知道怎么去使用,但是其中的一些加密原理,加密方式却只有少部分会去了解 ...

  8. 【移动开发】binder阻塞/非阻塞与单向/双向的问题

    The client thread calling transact is blocked by default until onTransact has finishedexecuting on t ...

  9. Java遍历时删除List、Set、Map中的元素(源码分析)

    在对List.Set.Map执行遍历删除或添加等改变集合个数的操作时,不能使用普通的while.for循环或增强for.会抛出ConcurrentModificationException异常或者没有 ...

  10. Android反编译 -- 错误代码还原

    PS:如果阅读体验不好,可以尝试Github版 (<-点左边) 1. setColor(-16777216) 反编译的代码中会有很多setColor(int)的情况,比如setColor(-16 ...