Canvas绘图之PorterDuffXfermode

本文介绍了在Android中使用Canvas绘图时PorterDuffXfermode的作用,通过实例展示了如何设置不同的Mode来改变两个bitmap重叠时的绘制效果,并探讨了硬件加速对Xfermode的影响,强调了只有在canvas.drawBitmap时才能看到正确的混合效果。

上一篇文章中简单介绍了一下Canvas绘图相关知识,留下了setXferMode未作介绍。此篇文章针对使用setXferMode中碰到的问题,做一个总结。

很多开发者都知道,PorterDuffXfermode用来设置两个bitmap重叠时的绘制效果(据说Porter和Duff是最早提出图形混合概念的两个人),网上到处可以看到这张图~

这里写图片描述

(dst表示底图,src表示要绘制的图)
它对每种Mode的描述已经非常清楚了。比如SrcIn就是绘制两个bitmap重叠的部分,绘制时使用src bitmap的Paint效果。于是自己动手尝试写个demo来实现这些效果。
一、俗话说实践出真知,如果不亲自写一遍,我永远都不知道这里面有哪些坑。实践从下面这段代码开始:
@Override
    protected void onDraw(Canvas canvas) {
        // 绘制一个圆
        mPaint.setColor(getResources().getColor(R.color.colorBlue));
        canvas.drawCircle(200, 200, 200, mPaint);
        // 绘制一个矩形
        mPaint.setColor(getResources().getColor(R.color.colorYellow));
        canvas.drawRect(200, 200, 600, 600, mPaint);
    }

上面代码绘制一个圆形和一个矩形,运行效果如下:
这里写图片描述

二、现在让我们来设置一个PorterDuff.Mode.CLEAR:
    @Override
    protected void onDraw(Canvas canvas) {
        // 绘制一个圆
        mPaint.setColor(getResources().getColor(R.color.colorBlue));
        canvas.drawCircle(200, 200, 200, mPaint);

        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
        // 绘制一个矩形
        mPaint.setColor(getResources().getColor(R.color.colorYellow));
        canvas.drawRect(200, 200, 600, 600, mPaint);
    }

按官方描述,应该是清空画布,显示空白。但是实际运行效果确是如下:
这里写图片描述
SRC_IN的运行效果甚至跟不加任何Mode一模一样。

瞬间蒙圈,是不是自己哪里错了呢,怎么跟官方效果差距那么大。各种搜索之后,发现要使用Xfermode,要关闭硬件加速:

// 构造函数中加上此项,可以关闭硬件加速功能
setLayerType(View.LAYER_TYPE_SOFTWARE, null);

关闭硬件加速功能之后,设置Mode.SRC_IN后再次尝试,效果似乎有点不同:
这里写图片描述
对比官方效果,还是不一样…

三、于是想到圆形ImageView的绘制过程
// 绘制一个圆
mPaint.setColor(getResources().getColor(R.color.colorBlue));
canvas.drawCircle(200, 200, 200, mPaint);

srcBitmap = ((BitmapDrawable)getDrawable()).getBitmap();
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(srcBitmap, 0, 0, mPaint);

此处先绘制了一个圆形,然后绘制了一个Bitmap,用SRC_IN模式来处理重叠。效果如下:
这里写图片描述
效果符合预期。
于是想会不会只有在绘制bitmap的时候才能正确实现PorterDuff的各种效果。于是那上面的代码作如下修改:

// 绘制一个圆
        mPaint.setColor(getResources().getColor(R.color.colorBlue));
        canvas.drawCircle(200, 200, 200, mPaint);

        mPaint.setColor(getResources().getColor(R.color.colorYellow));
        // 创建一个空白的bitmap
        Bitmap srcBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
        // 将bimtap传入一个canvas中,可以理解为将bitmap附着在画布上
        Canvas srcCanvas = new Canvas(srcBitmap);
        // 在上面生成的画布上面绘制一个矩形,实际上是绘制在bitmap上面
        srcCanvas.drawRect(200, 200, 600, 600, mPaint);

        // 将上面的bitmap绘制出来并使用SRC_IN重叠模式
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        canvas.drawBitmap(srcBitmap, 0, 0, mPaint);

运行效果:
这里写图片描述
此时运行效果就是我们想要的效果。
继续尝试其他的Mode,也都是正确的效果。

四、此时发觉,绘制在上层,也就是src图层,一定要是bitmap,即canvas.drawbitmap()时才可以出现正确的重叠效果。

看下图:
这里写图片描述
Xfermode是用来描述DstBitmap和SrcBitmap的混合模式。因此要使用drawBitmap来进行绘制才会出效果。

五、简单理解Mode

Mode.SRC_IN:表示 用SRC的画笔,绘制出SRC与DST相交的部分
Mode.DST_IN:表示 用DST的画笔,绘制出SRC与DST相交的部分。
Mode.SRC_OVER:SRC图在DST上方
Mode.DST_OVER:DST图在SRC上方
Mode.XOR:绘制出两图不相交部分
其他见顶部效果图。

Demo:https://github.com/ericzhaowei/Xfermode

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值