菜鸡wing遇敌PorterDuffXferMode,不料过于轻敌,应战吃力。

随后与其大战三天三夜。三百余回合不分胜负。

幸得 @咪咪控 相助,侥幸获胜。

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

跑起来的结果是这种:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />

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

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />

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

如今的效果是这种:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />

加一个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

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />

一致的!

!!

好激动有没有。!

!搞了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); }

效果例如以下:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />

能够看有效果了!!。! 可是是一个什么鬼。!

!  矩形缺角??加蓝色一点??

这样看是非常难看出效果的。。来调整一下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模式

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />

dst_in

那么把bitmap底色去掉。 改成透明的呢?

dst_in:

SRC_IN:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />


总结3:两个bitmap位置不全然重叠的效果如上,并不能总结出效果。要按实际效果来。

---------------------------------------------------------------------------------------------------------华丽丽的切割线-----------------------------------------------------------------------------------------

最终大总结,假设想让PorterDuffXferMode依照预期Demo(或者效果图)的效果图像实现,必须满足下面条件:


1、关闭硬件加速。

2、两个bitmap大小尽量一样。

3、背景色为透明色。

4、假设两个bitmap位置不全然一样,可能也是预期效果,仅仅只是你看到的效果和你自己脑补的预期效果不一致。


最后想再说几句。

鼓捣这个模式鼓捣了差点儿一周。每天晚上下班都在搞。查了无数资料。可是好多不完整。甚至有一些误导性。

所以为了避免后来者入坑。亲自试验,尽量总结。 假设有说的不对的地方请及时向我提出。我会及时改正。


假设本文帮助到了你。请点一个顶。或者评论一下,蟹蟹!

!!


PorterDuffXferMode不对的真正原因PorterDuffXferMode深入试验)的更多相关文章

  1. PorterDuffXferMode不正确的真正原因PorterDuffXferMode深入试验)

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

  2. PorterDuffXfermode 图像混合技术在漫画APP中的应用

    此文已由作者游葳授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 写在开头 随着应用开发的深入,视觉同学在完成了页面的基本设计后,再也按耐不住心中的寂寞,开始对各种细节不满意, ...

  3. excel求和结果不对

    excel求和结果不对 Excel求和功能是excel中最常用的功能,但是很多时候会碰到各种错误,比如求和结果总是0.公式求和结果和用计算器敲出来的结果不一样.更新了数据但是求和结果没有变等等.本经验 ...

  4. Android Paint Xfermode 学习小结

    一.setXfermode(Xfermode xfermode) Xfermode国外有大神称之为过渡模式,这种翻译比较贴切但恐怕不易理解,大家也可以直接称之为图像混合模式,因为所谓的"过渡 ...

  5. HttpClient Coder Example

    Example 1:   HttpClient httpClient = new HttpClient();                 httpClient.getHostConfigurati ...

  6. Effective java笔记(六),方法

    38.检查参数的有效性 绝大多数方法和构造器对于传递给它们的参数值都会有限制.如,对象引用不能为null,数组索引有范围限制等.应该在文档中指明所有这些限制,并在方法的开头处检查参数,以强制施加这些限 ...

  7. (转)SQL 优化原则

    一.问题的提出 在应用系统开发初期,由于开发数据库数据比较少,对于查询SQL语句,复杂视图的的编写等体会不出SQL语句各种写法的性能优劣,但是如果将应用 系统提交实际应用后,随着数据库中数据的增加,系 ...

  8. Oracle之常见问题诊断方法

    Oracle认证:常见问题诊断方法如下: 1.TNS-12154 Error 或ORA-12154 特征:SQL*NET没有找到连接串或别名 原因1:(1)没有找到TNSNAMES.ORA文件,该文件 ...

  9. AuthenticationManager.SignOut() 无法注销用户的问题

    http://hadb.me/2015/03/23/authenticationmanager-signout-not-working/ 这文章不对, 我发现原因是不能有Response.Redire ...

随机推荐

  1. Apache CXF实战之四 构建RESTful Web Service

    Apache CXF实战之一 Hello World Web Service Apache CXF实战之二 集成Sping与Web容器 Apache CXF实战之三 传输Java对象 这篇文章介绍一下 ...

  2. static静态变量-投票案例

    public class Voter { String name; //名字 private static int count; //投票数 public Voter() {} public Vote ...

  3. 图论常用算法之一 POJ图论题集【转载】

    POJ图论分类[转] 一个很不错的图论分类,非常感谢原版的作者!!!在这里分享给大家,爱好图论的ACMer不寂寞了... (很抱歉没有找到此题集整理的原创作者,感谢知情的朋友给个原创链接) POJ:h ...

  4. Java多线程设计模式(2)生产者与消费者模式

    1 Producer-Consumer Pattern Producer-Consumer Pattern主要就是在生产者与消费者之间建立一个“桥梁参与者”,用来解决生产者线程与消费者线程之间速度的不 ...

  5. adb devices 找不到设备怎么办 --- 2

    问题现象:在电脑上安装好手机驱动后,手机进入设置---->应用程序---->开发----->勾选USB调试后连接电脑,,在CMD命令中输入adb devices发现没有设备. 解决方 ...

  6. 玩转Nuget服务器搭建(二)

    之所以分开来写这几部分,是因为今天搭建的过程中,碰到了几个问题,特别提一下,让大家省下这部分时间(毕竟人生苦短嘛,你如果就是闲的蛋疼,请给我你的GUID,我送你几瓶风油精). NugetServer ...

  7. Python数据结构:序列(列表[]、元组())与映射(字典{})语法总结

    一.概述:Python中两种基本的数据结构是序列和映射,序列包含:可变的列表和不可变的元组:而当序列不够用时就出现了映射:字典.列表中的元素是可以变化的,元组里面的元素一旦初始化后就不可更改.列表和元 ...

  8. 【转】Kriging插值法

    einyboy 原文LINK Kriging插值法 克里金法是通过一组具有 z 值的分散点生成估计表面的高级地统计过程.与插值工具集中的其他插值方法不同,选择用于生成输出表面的最佳估算方法之前,有效使 ...

  9. VBO与VAO 【转】

    我想大家都已经熟悉VBO了吧.在GL3.0时代的VBO大体还是处于最重要的地位,但是与此同时也出现了不少新的用法和辅助役,其中一个就是VAO.本文大致小记一下这两者的联系,帮助大家理解一下这个角色.— ...

  10. jqGrid怎么设置初始化页面时不加载数据(不向服务器请求数据)

    最近做一些表格一直用到jqGrid,今天遇到一个问题: 1.就是页面加载的时候数据不显示,点击搜索才根据请求从服务器返回并显示内容. 2.默认不从服务器请求数据(不然在开发者工具下会显示请求不到数据的 ...