如题
我发现,用canvas绘图如果只是创造一些图形倒还容易,无非就是麻烦一点。
但是我居然一下想不到怎么从图像中扣出一个透明的圆形来。
方形的很容易嘛,可以在四周绘制几个方形,把中间空出来就可以了,已经实现了。但是没办法让中间空出一个圆形的来。
比如说,类似扫码的界面,就中间一个扫码区域可用,其他区域是半透明的,或者是一个蒙版,把需要特写的地方空出来,其他地方是半透明的。
找到了两个解决办法
第一个方法:使用paint,setStrokeWidth.
在绘图的时候,需要设置paint,如果绘制一个圆形,把paint设置成stroke,就会绘制一个带边线的圆形,但是效果不是上面提到的那样的中空的。
但是,如果把strokeWidth设置的很宽,就可以模拟出这种效果。具体的试一下就知道了。
其中,设置的宽度是在原边线的位置,往外和往内各绘制0.5个宽度,加起来就是1个宽度了。
缺点:空出来的空间大了还好,看不出来毛病(几乎看不出来)。如果中间的圆小了,就看得出来那实际上是个多边形,貌似是个6变形。
第二个方法,绘图的时候,paint有个方法 :setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
如果设置了这个,那么,绘出来的图形会在之前绘制的图形上面扣出来,比如,之前绘制的是个方形,然后在中间绘制一个圆形,那么这个圆形就会在中间扣出来,而不是原来的叠加圆形。这个貌似是最容易想到的过程。但是
缺点:貌似不能应用在硬件加速的组件上。如果直接在onDraw里面绘制,那需要关闭硬件加速,不用全局关,只要设置当前view关闭硬件加速即可。如果是绘制在bitmap上,然后在onDraw里面绘制bitmap,倒是可以不关闭硬件加速。
但是,我现在需要做一个揭露效果,就是开始描述的那个圆形慢慢扩大,揭露出底下的内容。实际上,这个效果在5.0以后,material design里面直接提供了一个方法ViewAnimationUtils.createCircularReveal()
,直接就可以用。我现在是想用一个自己的思路实现这个效果。(好吧,就算是重复发明轮子吧)
如果使用第二个方法,那么揭露动画效果非常不连贯,就像帧数很低一样。即便是不关闭硬件加速的那种方法也是如此。
总结
如果使用普通的遮罩,并且在中间扣出一个洞来显示内容,第二个办法更好,可以扣的比较圆。
但是如果做动画,效果不行,用第一个办法,勉强可以。
因此,还需要继续探索有没有其他解决途径。
貌似最合理的解决办法来了
好,才过一会儿,我就在网上找到了最合理的解决办法。
canvas有一系列的clip方法,包括两个clipRect和两个clipPath
对应另种切割,分别是方形切割和path切割。如果要切割圆形,就用第二个也就是clipPath
两组方法里面参数类似,就拿clipPath来讲,分别是
clipPath(Path path)
和clipPath(Path path, Region.Op op)
如果要切割区域,需要调用两次,第一次调用第一个方法,第二次第二个,
其中第二个方法的op参数确定了切割类型
//DIFFERENCE是第一次不同于第二次的部分显示出来
//REPLACE是显示第二次的
//REVERSE_DIFFERENCE 是第二次不同于第一次的部分显示
//INTERSECT交集显示
//UNION全部显示
//XOR补集 就是全集的减去交集剩余部分显示
DIFFERENCE是第一次不同于第二次的部分显示出来A-B-------
REPLACE是显示第二次的B******
REVERSE_DIFFERENCE 是第二次不同于第一次的部分显示--------
INTERSECT交集显示A-(A-B)*******
UNION全部显示A+B******
XOR补集 就是全集的减去交集剩余部分显示--------
流程是,先调用clip方法两次,确定切割区域
然后再调用普通的绘图方法,绘制图形
最后显示出来的就是clip方法确定的东西了。
用这个方法来绘制静态的抠图没问题,经过测试发现,做一个揭露动画的话,效果也比之前介绍的那个需要关闭硬件加速的好多了,帧数正常,我肉眼观察来看,跟官方提供的那个ViewAnimationUtils.createCircularReveal()
没区别。
http://www.cnblogs.com/bbglz/p/4794519.html
http://1025250620.iteye.com/blog/1933226
所以,重复发明轮子成功…………
好吧,这种事情还是研究下就算了,要用的话还是用官方提供的那个。