Android實(shí)現(xiàn)點(diǎn)擊Button產(chǎn)生水波紋效果
先上圖,看看接下來我要向大家介紹的是個什么東西,如下圖:
接下來要介紹的就是如何實(shí)現(xiàn)上述圖中的波紋效果,這種效果如果大家沒有體驗(yàn)過的話,可以看看百度手機(jī)衛(wèi)士或者360手機(jī)衛(wèi)士,里面的按鈕點(diǎn)擊效果都是這樣的,另外Android 5.0以上的版本也出現(xiàn)了這種效果。不多說,下面聊聊具體的怎么實(shí)現(xiàn)。
首先大家看到的是三個button,水波紋的出現(xiàn)給我們的錯覺是直接將波紋繪制在button上面的,但是這樣能做到嗎?首先button自己有background和src,如果把半透明的水波紋當(dāng)作background或者src繪制到button上面,肯定是會損失button原有的樣式的??赡苡信笥巡孪肽蔷桶阉y繪制在屏幕上唄,恭喜這位朋友答對了,至少我是這么干的,具體思路就是,我們自己實(shí)現(xiàn)一個layout,在layout中捕捉事件,并對事件進(jìn)行相應(yīng)的處理,在down事件中尋找當(dāng)前用戶點(diǎn)擊的是哪個view,找出view所在的矩形區(qū)域,將一個透明的圓環(huán)繪制到這個矩形區(qū)域,在up事件中,延時分發(fā)view的onclick事件。
- 1、自己實(shí)現(xiàn)一個layout:
- 2、重寫layout的dispatchTouchEvent方法,在down事件中找出被點(diǎn)擊的view。
public View findTargetView(float x, float y, View anchorView) { ArrayList<View> touchablesView = anchorView.getTouchables(); View targetView = null; for (View child : touchablesView) { RectF rectF = getViewRectF(child); if (rectF.contains(x, y) && child.isClickable()) { // 這說明被點(diǎn)擊的view找到了 targetView = child; break; } } return targetView; }
接著找出view所在的矩形區(qū)域,因?yàn)橐獙⒉y繪制到該區(qū)域:
public RectF getViewRectF(View view) { int[] location = new int[2]; view.getLocationOnScreen(location); int childLeft = location[0]; int childTop = location[1]; int childRight = childLeft + view.getMeasuredWidth(); int childBottom = childTop + view.getMeasuredHeight(); return new RectF(childLeft, childTop, childRight, childBottom); }
矩形區(qū)域找到之后,這個區(qū)域就是我們要繪制的博波紋所在地,上面也說過了,波紋其實(shí)就是圓環(huán),繪制圓的畫是需要知道圓心坐標(biāo)和圓的半徑,圓心坐標(biāo)肯定就是down時候的x和y了,但是半徑怎么計算合適?大家看到上面的圖知道如果view的寬度大于高度,點(diǎn)擊view的左下角或者右下角,那么半徑基本上就是等于view的寬度,點(diǎn)擊view的上部或者下部分,半徑就是在0和view的高度之間,具體的計算方式看下圖:
那么根據(jù)上圖,半徑的計算方式就應(yīng)該是:
float left = circleCenterX - targetTouchRectF.left; float right = targetTouchRectF.right - circleCenterX; float top = circleCenterY - targetTouchRectF.top; float bottom = targetTouchRectF.bottom - circleCenterY; // 計算出最大的值則為半徑 rawRadius = Math.max(bottom, Math.max(Math.max(left, right), top));
半徑算出來了,雖說圓心就是down時的x和y,但是有個地方還是需要注意的,在繪制圓環(huán)的時候提供的圓心坐標(biāo)的x和y是在本文中是相對于layout的,所以在計算y的時候是需要進(jìn)行一定處理的:
/** * 獲取圓環(huán)的中心坐標(biāo) */ public float[] getCircleCenterPostion(float x,float y){ int[] location = new int[2]; float[] mDownPositon = new float[2]; getLocationOnScreen(location ); mDownPositon[0] = x; mDownPositon[1] = y -location[1]; return mDownPositon; }
圓心坐標(biāo)和半徑都計算好了,記下來就可以繪制圓形波紋了,那么在哪里繪制這個波紋比較合適呢?有朋友立馬就說肯定是在onDraw方法里面繪制了,那么恭喜你在我看來你是答錯了,我們的layout中是很有很多childview的,而layout是個viewGroup,viewGroup在繪制的時候,是先繪制自身的背景,再繪制自身,再繪制childview,如果在onDraw中繪制波紋,也就意味者后面繪制出來的childView會將我們的波紋遮蓋,所以我們就應(yīng)該等到childview繪制完畢后再來繪制波紋,這樣可以保證childview在最頂層。
重寫dispatchDraw方法:
@Override protected void dispatchDraw(Canvas canvas) { super.dispatchDraw(canvas); /** * 繪制完子元素后開始繪制波紋 */ if (mTargetTouchView != null) { RectF clipRectF = clipRectF(mTargetTouchView); canvas.save(); // 為了不讓繪制的圓環(huán)超出所要繪制的范圍 canvas.clipRect(clipRectF); if(drawedRadius < rawRadius){ drawedRadius += rawRadius / drawingRadiusDegrees; canvas.drawCircle(mDownPositon[0], mDownPositon[1], drawedRadius, mHalfTransPaint); postInvalidateDelayed(INVALID_DURATION); }else{ canvas.drawCircle(mDownPositon[0], mDownPositon[1], rawRadius, mTransPaint); post(delayedRunnable); } canvas.restore(); } }
在分發(fā)繪制事件中大家可以看到,波紋是一段一段的繪制,形如下圖:
而這一段段的波紋正是通過繪制一個個的圓環(huán)實(shí)現(xiàn)的,所以在沒繪制完畢一個圓環(huán)的時候,都需要延時重新繪制下一個圓環(huán)。
通過上面波紋效果基本上完成了,但是按鈕是有點(diǎn)擊事件的,像360手機(jī)衛(wèi)士或者百度手機(jī)衛(wèi)士等都是等波紋效果播放完畢后才會響應(yīng)點(diǎn)擊事件,所以我們這里也要對這個點(diǎn)擊事件進(jìn)行延時響應(yīng)。
在up事件中,記錄此次事件的event,并且返回true,表示消費(fèi)此次的事件,然后再圓環(huán)繪制完畢后,再利用找到的view去分發(fā)這個event:
if (ev.getAction() == MotionEvent.ACTION_UP) { // 需要讓波紋繪制完畢后再執(zhí)行在up中執(zhí)行的方法 // if(drawedRadius==0){ // return false; // } // long totalTime = (long) (INVALID_DURATION * (drawingRadiusDegrees+5)); // // 離波紋結(jié)束的時間 // long time = (long) (totalTime - drawedRadius*totalTime / rawRadius); delayedRunnable.event = ev; return true; } class postUpEventDelayed implements Runnable{ private MotionEvent event; @Override public void run() { if(mTargetTouchView!=null && mTargetTouchView.isClickable() && event!=null){ mTargetTouchView.dispatchTouchEvent(event);// 分發(fā) } } }
在dispatchDraw方法中,判斷如果繪制完畢就post(delayedRunnable);執(zhí)行childView的事件延時分發(fā)。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)Android程序設(shè)計有所幫助。
- Android特效之水波紋的實(shí)現(xiàn)
- Android仿水波紋流量球進(jìn)度條控制器
- Android項(xiàng)目實(shí)戰(zhàn)手把手教你畫圓形水波紋loadingview
- Android實(shí)現(xiàn)水波紋特效
- Android實(shí)現(xiàn)水波紋效果
- Android自定義View 實(shí)現(xiàn)水波紋動畫引導(dǎo)效果
- Android 自定義view實(shí)現(xiàn)水波紋動畫效果
- Android實(shí)現(xiàn)自定義華麗的水波紋效果
- Android自定義View控件實(shí)現(xiàn)多種水波紋漣漪擴(kuò)散效果
- Android實(shí)現(xiàn)漸變色水波紋效果
相關(guān)文章
android傳送照片到FTP服務(wù)器的實(shí)現(xiàn)代碼
這篇文章主要為大家詳細(xì)介紹了android傳送照片到FTP服務(wù)器的實(shí)現(xiàn)代碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-06-06Android 1.5 1.6 2.0 2.1 2.2 的區(qū)別詳解
本篇文章是對Android 1.5 1.6 2.0 2.1 2.2 版本之間的區(qū)別進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-06-06Android實(shí)現(xiàn)底部導(dǎo)航欄的主界面
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)底部導(dǎo)航欄的主界面 ,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-09-09Android編程實(shí)現(xiàn)為ListView創(chuàng)建上下文菜單(ContextMenu)的方法
這篇文章主要介紹了Android編程實(shí)現(xiàn)為ListView創(chuàng)建上下文菜單(ContextMenu)的方法,簡單分析了上下文菜單的功能及ListView創(chuàng)建上下文菜單(ContextMenu)的具體步驟與相關(guān)操作技巧,需要的朋友可以參考下2017-02-02Android仿微信發(fā)表說說實(shí)現(xiàn)拍照、多圖上傳功能
這篇文章主要為大家詳細(xì)介紹了Android仿微信發(fā)表說說實(shí)現(xiàn)拍照、多圖上傳功能,使用Retrofit2.0技術(shù),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-03-03clipse項(xiàng)目遷移到android studio的方法(圖文最新版)
這篇文章主要介紹了clipse項(xiàng)目遷移到android studio(圖文最新版),需要的朋友可以參考下2015-10-10Android百度地圖定位后獲取周邊位置的實(shí)現(xiàn)代碼
這篇文章主要為大家詳細(xì)介紹了Android百度地圖定位后獲取周邊位置的實(shí)現(xiàn)代碼,準(zhǔn)確獲取周邊地理位置,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-01-01Android 實(shí)現(xiàn)按兩次返回鍵退出程序(兩種方法)
這篇文章主要介紹了Android 實(shí)現(xiàn)按兩次返回鍵退出程序(兩種方法)的相關(guān)資料,這里不僅實(shí)現(xiàn)還對原理進(jìn)行了分析,需要的朋友可以參考下2017-07-07