Android 自定義波浪動畫 | 您所在的位置:網(wǎng)站首頁 › 隨便給別人算卦 › Android 自定義波浪動畫 |
waveview
《Android 自定義波浪動畫之"讓進(jìn)度浪起來~"》轉(zhuǎn)載請注明來自?傻小孩b_移動開發(fā)(http://www.jianshu.com/users/d388bcf9c4d3)喜歡的可以關(guān)注我,不定期總結(jié)文章!您的支持是我的動力哈! 前言首先貝塞爾曲線原理我在這里就不多說了,今天的重點(diǎn)還是講下怎么實(shí)現(xiàn)波浪進(jìn)度的實(shí)現(xiàn)原理,所以想要了解下貝塞爾曲線的程序yuan,請自己百度或者谷歌下哈,多謝合作~如果開發(fā)有什么問題也可以直接加入我的QQ群,詳情請看我的個(gè)人簡介。 演示waveview.gif WaveView 實(shí)現(xiàn) (一)如何確定初始化的位置? 首先在實(shí)現(xiàn)一個(gè)自定義View的時(shí)候,我們先來觀察下想要的動畫效果分為幾個(gè)層次,如圖所示: 1、向右的貝塞爾曲線,這里用“normal wave”來表示。? 作用:一直勻速向左的波浪曲線,作為波浪的前景 2、向右的貝塞爾曲線,這里用“rolling wave”來表示。? 作用:為了是波浪效果更佳逼真,所以添加了一個(gè)向右勻速的波浪曲線,并且滾動速度是“normal wave”的一半 3、波浪上升高度,這里用“wave height”來表示。? 作用:高度代表進(jìn)度,可以根據(jù)設(shè)置的當(dāng)前進(jìn)度progress與最大進(jìn)度max動態(tài)變化 其次在這里我們先要來說下貝塞爾曲線應(yīng)該怎么畫。剛開始,有可能有程序yuan想過,畫一個(gè)無限長(例如 Integer.MAX_VALUE),足夠大了、固定周期的賽貝爾曲線,然后開啟動畫讓他固定一個(gè)方向移動即可。的確,這種實(shí)現(xiàn)方式是可以的,但是感覺資源特別浪費(fèi),有可能還會出現(xiàn)內(nèi)存溢出、響應(yīng)異常等。所以答案:不建議! 當(dāng)然,上面那個(gè)思路,我是有著手嘗試過啦。最后還是擇優(yōu)選擇了另一個(gè)思路,畫出兩個(gè)周期的貝塞爾曲線,當(dāng)?shù)谝粋€(gè)貝塞爾曲線滑動到最后一個(gè)Point、接近第二個(gè)貝塞爾曲線的開始Point的時(shí)候,直接讓他復(fù)位,恢復(fù)到最初時(shí)候的狀態(tài),這種繪畫效果還是看起來比無限長的貝塞爾曲線效果沒區(qū)別的。所以,每一次,我們需要計(jì)算4n +1個(gè)Point點(diǎn),為什么要4n+1個(gè)點(diǎn)?下面圖片說明: Wave_1.png 最后就是整個(gè)閉合區(qū)間的填充,如圖所示: wave_2.png 我們看下動畫里面,初始化Point的關(guān)鍵代碼: /** * Initialize the original wave arts collection point , including normal wave ,rolling wave */ private void initPoint(){ if (isInitPoint){ isInitPoint = false; pointList.clear(); shadpointList.clear(); WAVE_WIDTH = (float) (VIEW_WIDTH / 2.5);//這里開發(fā) 我直接設(shè)置波浪寬度為整個(gè)View的四分之一寬度 WAVE_HEIGHT = VIEW_HEIGHT/getWaveHeight();//波浪高度根據(jù)速度改變 dy = VIEW_HEIGHT;//Started from the bottom, when the height is rise, dy gradually reduce //How many points calculated maximum support int n = Math.round(VIEW_WIDTH / WAVE_WIDTH); //start point for normal wave int startX = 0; Log.i(TAG,"begin point ("+DensityUtil.px2dip(mContext,startX)+" , "+DensityUtil.px2dip(mContext,dy)+")"); for (int i = 0; i < 4*n+1; i++) { .... pointList.add(point); } // start point for rolling wave startX = (int) VIEW_WIDTH; for (int i = 0; i < 4*n+1; i++) { .... shadpointList.add(point); } } }從上面的代碼,我們可以觀察到“normal wave”和“rolling wave”初始化Point各自存儲在一個(gè)list上面,并且先根據(jù)波浪的寬度與整個(gè)View的寬度,計(jì)算出最多支持多少個(gè)初始化點(diǎn)(非控制點(diǎn),一個(gè)周期最多三個(gè)Point) int n = Math.round(VIEW_WIDTH / WAVE_WIDTH); 因此便能計(jì)算出4n+1個(gè)point的初始化位置。 (二)如何浪起來?我們直接定位在移動的動畫方法flowingAnimation,根據(jù)代碼,我們可以了解到使用了屬性動畫。 private void flowingAnimation(){ ObjectAnimator animator = ObjectAnimator.ofFloat(this,"wave",0,100) .setDuration(100); animator.setRepeatCount(INFINITE); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { dx = dx + speed; shd_dx = shd_dx + speed/2;//Half the speed of the normal waves .... rerefreshPoints();//更新初始化點(diǎn) postInvalidate(); } }) ; animator.start(); }從代碼可以觀察到,是屬于一個(gè)無限循環(huán)的動畫( animator.setRepeatCount(INFINITE);),并且動態(tài)變化的是dx與shd_dx。因此可以直接觀察在繪制onDraw里面,這兩個(gè)動態(tài)變化的變量起了什么作用,以下截取部分onDraw的代碼: for (int i = 0; i < pointList.size(); i++) { int j = i + 1; if (pointList.size() > i) { float start1 = pointList.get(i).x; wavePath.moveTo(start1, dy);//+dy if (j % 2 == 0 && j >= 2) { ... } else { .... }} } .... for (int i = 0; i < shadpointList.size(); i++) { int j = i + 1; if (shadpointList.size() > i) { float start1 = shadpointList.get(i).x + shd_dx; shadPath.moveTo(start1, dy);//+dy if (j % 2 == 0 && j >= 2) { .... } else { .... } } }應(yīng)該很明顯可以觀察到,dx是改變“normal wave”周期的起點(diǎn),shd_dx是改變“rolling wave”周期起點(diǎn),因此間接使貝塞爾曲線雙向”浪起來“,有了波浪的效果。 (三)如何浮起來?直接進(jìn)入動畫,觀察動態(tài)變化的變量 private void riseAnimation(){ .... if (dy > 0) { ... ValueAnimator animator = ValueAnimator.ofFloat(0, s) .setDuration(500); animator.setInterpolator(new LinearInterpolator()); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { ... dy = s; Log.i("yuan", "move m " + m + "dy " + dy); } }); animator.start(); beforDy = sum_dy - sum_dy * progressRatio;//save the last time the higher level } }從代碼可以觀察到,動態(tài)變化的是dy,因此波浪浮動的高度由dy所決定,這里難點(diǎn)是這么計(jì)算出當(dāng)我們設(shè)置max和progress的時(shí)候,動態(tài)去變化dy,這里我用一張圖來解釋下: (四)回調(diào)監(jiān)聽感覺回調(diào)監(jiān)聽感覺沒有好說的~ 首先WaveView是在onDraw進(jìn)行回調(diào)的,但是這里來有個(gè)小問題,如果我們頻繁的繪制,不處理的話每一次都會進(jìn)行回調(diào),這樣也會造成不必要的浪費(fèi)。因此這里,簡單記錄上次的進(jìn)度,通過對比,不同才回調(diào)。 (五)總結(jié)二十幾天沒總結(jié),這期間搞了點(diǎn)東西,也經(jīng)歷了一個(gè)放松的國慶~當(dāng)然,同志們也不能將開發(fā)落下~最后還是:我們也不能只是搬運(yùn)代碼的“程序猿”,更重要我們是需要寫出更高質(zhì)量的代碼,創(chuàng)造的“程序猿”。下面附上源碼,如果喜歡的話給個(gè)star哈~謝謝: WaveView 讓進(jìn)度浪起來~ 使用方法,可以直接上github看README 傻小孩b mark共勉,寫給在成長路上奮斗的你 喜歡就為我點(diǎn)下喜歡、給我個(gè)github的star吧~ 感謝各位讀者閱讀。 |
今日新聞 |
推薦新聞 |
專題文章 |
CopyRight 2018-2019 實(shí)驗(yàn)室設(shè)備網(wǎng) 版權(quán)所有 |