最近找工作,面試遇到了一個問題問抖音的那個錄制按鈕效果如何實現。說到這里熟悉自定義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);
那么就出現下面這樣的效果

本人菜鳥一枚,文章淺陋,有不當之處還望批評指正。
