最近在做一款類似FaceU的App,需要做短按拍照,長按錄像功能,雖然長按只需要LongClickListener就好了,但是要同時做出動畫效果。
在網(wǎng)上轉(zhuǎn)了一圈,發(fā)現(xiàn)仿微信長按錄像的不少,例如這個,但是仿FaceU的好像還沒有,所以決定自己寫一個。
先放一張效果圖:

一、實(shí)現(xiàn)流程分析
按鈕要實(shí)現(xiàn)類似ClickListener和LongClickListener的功能,因此需要監(jiān)聽觸控事件
按照時間順序,按鈕的動畫效果大概是這樣:
- 還沒有到達(dá)LongClick的時間閾值,沒有任何反應(yīng),靜態(tài)的畫面為中間一個半透明白色圓形,外面一個白色圓環(huán)
- 動畫開始,中間的圓形消失,變成一個逐漸擴(kuò)大的綠色圓形
- 在綠色圓形擴(kuò)大的同時,外面的圓環(huán)擴(kuò)大,同時進(jìn)度條開始移動
- 綠色圓形和圓環(huán)擴(kuò)大到最大值
- 進(jìn)度條滿,達(dá)到錄像的時間閾值或用戶手指離開(ACTION_UP)
此外,還有兩個黑色半透明的圓環(huán)作為描邊,但是效果不是很明顯,略去不表。
二、代碼實(shí)現(xiàn)
這種效果,拿自定義View來做再合適不過了,整個動畫不需要任何素材,可以直接通過重寫View的draw函數(shù)實(shí)現(xiàn)。
分配率無關(guān)的尺寸獲取
我們希望繪制出的圖形在不同屏幕上都顯示類似的效果,所以要獲取一個像素密度相關(guān)的尺寸
public int getRefLength(float len) {
return (int) (mContext.getResources().getDisplayMetrics().density * len + 0.5F);
}
圓形/圓環(huán)的繪制
圓形/圓環(huán)的繪制比較簡單,只需要設(shè)定Paint的屬性,然后在onDraw里面交給canvas即可。如果是圓環(huán),那么類型就是Style.STROKE,實(shí)心圓是Style.FILL_AND_STROKE
centerCirclePaint = new Paint();
centerCirclePaint.setColor(colorWhiteP60);
centerCirclePaint.setAntiAlias(true);
centerCirclePaint.setStyle(Style.FILL_AND_STROKE);
canvas.drawCircle(centerX, centerY, innerCircleRadiusToDraw, centerCirclePaint);
圓弧的繪制
圓弧的繪制比較類似,但是調(diào)用的是不同的函數(shù),給定的是圓弧的包圍矩形,另外我們希望進(jìn)度條從最上面開始,所以我們的起始角度是270度(0度是右邊)
canvas.drawArc(outMostCircleRect, startAngle270, 360.0F, false, outMostWhiteCirclePaint);
LongClick狀態(tài)判斷
如何判斷用戶是單擊還是長按呢?
我們可以監(jiān)聽用戶的觸摸事件,設(shè)定一個超時的閾值,如果用戶按下超過這個時間,那么就是長按,否則就是單擊。
超時判斷可以采用一個定時的消息,或者每隔一小段時間檢查一下。
public boolean onTouchEvent(MotionEvent e) {
switch (e.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.d(TAG, "onTouchEvent: down");
startTicking();
break;
case MotionEvent.ACTION_MOVE:
Log.d(TAG, "onTouchEvent: move");
break;
case MotionEvent.ACTION_UP:
Log.d(TAG, "onTouchEvent: up");
reset();
break;
}
return true;
}
動畫時限
中間圓形的縮放時間和錄制時間是不一樣的,我們要分開處理進(jìn)度條的動畫和中間圓形按鈕的動畫。
可以考慮設(shè)定一個比例10%,表示如果錄制視頻的時限為5秒,那么圓形在0.5秒時縮放到最大。
事件回調(diào)
在獲取到點(diǎn)擊和長按的動作并且顯示對應(yīng)的動畫以后,我們需要將這個消息傳出去。
設(shè)定一個這樣的監(jiān)聽器:
public interface ClickListener {
void onClick();
void onLongClickStart();
void onLongClickEnd();
}
- 當(dāng)用戶ACTION_DOWN沒有超過閾值時,onClick被調(diào)用
- 當(dāng)用戶ACTION_DOWN剛好超過閾值時,onLongClickStart被調(diào)用
- 當(dāng)用戶ACTION_DOWN超過閾值后離開或者錄制時間達(dá)到限制時onLongClickEnd被調(diào)用
三、為不同配色的App定制
根據(jù)前面的分析,我們的按鈕主色調(diào)是綠色,如果應(yīng)用在其他App中,只需要改主色調(diào),其他不變即可。
改成橙色試試?
