最近找工作,面试遇到了一个问题问抖音的那个录制按钮效果如何实现。说到这里熟悉自定义View的话,很容易就想到这里关键是考Xfermode的了解及使用。
话不多说先上图
现在就让我们来动手实现吧。这里控件的效果就要用到自定义VIew中重写OnDraw ()方法来实现了。
首先分析思路
1.这个动画初看的话也就是两个圆重叠,然后内部圆半径发生变化
2.重叠的圆石镂空的
3.xfermode可以解决图形重叠的绘制区域的问题
在这里先看一下xfermode经典的图形处理
在这里看到我们的外圆就是Dst,内圆就是src,我们要拿到的区域便是Dstout对应的区域,所以我们需要采用PorterDuff.Mode.DST_OUT模式
到这里思路已经很清晰了,下面就开始上代码
具体实现
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //移动画布到控件中间 canvas.translate(mViewWidth/2,mViewHeight/2); //这里没有对圆环大小做控制,只是为了测试效果,如果需要可以作为view属性 //这是是个外圆半径200,内圆半径在150-190直接变化 //动态计算内圆半径 float offset = 150 + 40 * mAnimatorValue; //先画外圆 mPaint.setColor(Color.RED); canvas.drawCircle(0,0,200,mPaint); //设置Xfermode为DST_OUT模式 mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); //画内圆 canvas.drawCircle(0,0,offset,mPaint); //重置Xfermode mPaint.setXfermode(null); }
到这里已经跑起来就已经实现了这个动画效果,mAnimatorValue这个是通过属性动画来动态获取进度值,收缩动画通过修改内圆半径来实现。
注意事项
动画执行需要设置硬件加速或者软件加速,执行完需要关闭
mStartAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { super.onAnimationStart(animation); setLayerType(LAYER_TYPE_HARDWARE,null); setLayerType(LAYER_TYPE_HARDWARE,null); //这里也可以设置LAYER_TYPE_SOFTWARE,可以达到同样的效果 } @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); setLayerType(LAYER_TYPE_NONE,null); } });
这里要注意的是如果执行动画不设置
setLayerType(LAYER_TYPE_HARDWARE,null);
那么就出现下面这样的效果
本人菜鸟一枚,文章浅陋,有不当之处还望批评指正。