安卓Canvas绘图之setXfermode一个需要注意的点

今天做一个自定义控件,给TV应用的item设置背景,但是UI给的背景图套在item背后,会有黑边在item内部,当item图片没显示出来的时候,会显示出这个背景图,
这里写图片描述
因为item是很多大小不一的,但都用了同一个背景,这个背景是个.9图,而我希望在不修改图的前提下,使得item显示效果都是一样的,即只显示item边以外的部分,item边内的自然不可见,于是只能在代码中实现,刚开始想到了canvas.clipRect(),后来发现不太好搞,它是圈住了个区域,在区域内绘图,与我需求不符,于是又想到了setXfermode这个强大的API,其中的混合模式正好符合需求,说干就干。
经过查阅相关资料,确定了如下简单代码:

        /…这是在onDraw()里…/
        canvas.drawBitmap(shadowImg,null,dstRect,null);
        canvas.drawRoundRect(tmpRect,10,10,bitmapPaint);
        bitmapPaint.setXfermode(xfermode);
        canvas.drawRoundRect(tmpRect,10,10, bitmapPaint);
        /……/

其中dstRect是目标显示区域,tmpRect是内部需要裁剪的区域,xfermode是我在外部定义好的:

     xfermode = new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT);

这个Mode很关键,SRC_OUT指的是保留非重叠的部分,而SRC_IN保留的是两个图重叠的部分,也就是交集。这个试一下就理解了。更多模式,参考百度的资料吧,太多了,介绍的也很详细,我这里只强调一个需要注意的地方。

由于我的代码涉及到onDraw重复执行,即获取焦点时绘制一次,失去焦点时再次绘制,而这时候,上面的代码会出现问题,就是第一次显示正常,内部阴影正常裁剪掉了,但是第二次获取焦点时,被裁剪掉的阴影又回来了,之后就一直都在显示。经查阅资料,原来这个涉及到canvas绘制的原理。而解决方法就是:

     int sc = canvas.saveLayer(0, 0, canvas.getWidth(), canvas.getHeight(), null, Canvas.ALL_SAVE_FLAG);
        canvas.drawBitmap(shadowImg,null,dstRect,null);
        canvas.drawRoundRect(tmpRect,10,10,bitmapPaint);
        bitmapPaint.setXfermode(xfermode);
        canvas.drawRoundRect(tmpRect,10,10, bitmapPaint);
        //还原
        bitmapPaint.setXfermode(null);
        canvas.restoreToCount(sc);

savelayer意思就是新建一个图层,之后的操作都在这个图层上进行,然后走完流程后,关键点是记得将xfermode设为null,也就是去掉,savelayer 和restoreToCount()测试发现可有可无,不过出于科学敲代码,我们还是养成好习惯吧。最后实现的效果如下:
这里写图片描述

参考文章:https://blog.youkuaiyun.com/u013085697/article/details/52096703

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值