高仿path小球刷新效果,類似IOS果凍效果
一.概述
相信用過path app的人都會被其精美的效果給吸引到,作為一名用戶,我首先被其吸引都的就是其時間軸下拉刷新后類似于ios的果凍效果。同時作為一名coder,我們更應該好奇它是怎么實現的。于是乎,在百度的指引下,并沒有什么斬獲,既然如此,那就由我們自己擼出來吧!
下面看看我們自己擼出來的效果和path原裝效果的區別吧。(注意重點在小球的果凍效果哦O(∩_∩)O)
效果還是挺不錯的。下面就開始擼代碼之旅了~
二.分析
小球是會動來動去的,所以我們肯定不會笨到直接畫個圓來代替~那我們應該怎么辦呢?這時候就需要三次貝塞爾曲線來畫圓啦。
畫圓的學習我這里就不陳述了。大家可以看看這個大神寫的《三次貝塞爾曲線練習之彈性的圓》很有幫助!
現在接著往下走(我當你已經學會畫圓的技巧了`(∩_∩)′)
OK,假設我們已經有個一個圓
↓↓↓
參考path的下拉時效果:
- 下拉時,如果下拉距離低于某個值則松手會直接復位到正常狀態
(下拉過程中豎線上面的寬度變小,下面不變,小球在一定下拉范圍內寬度變小)- 若下拉距離大于某個值,則小球(圓)向下移動到某一個位置A
- 小球移動到位置A后若繼續下拉,則小球與豎線同時向下移動且之間距離不變
- 下拉過程中豎線上面的寬度變小,下面不變
→按照這個思路。說說我們的解決辦法吧。
下拉時我們的p1、p1.left、p1.right相關坐標改變 —->造成小球被拉伸效果
p2、p2.left、p2.right、p4.left、p4.right相關坐標改變 —->造成小球寬度變小,利用簡諧振動函數造成小球回彈效果。
要保持小球與豎線同時向下移動且之間距離不變則利用layout來改變即可
參考path的復位時效果:
小球復位
復位后小球實現回彈抖動的效果
其實有了之前下拉的分析,復位也幾乎類似,唯一需要注意的是,小球移動到位置A后若繼續下拉,則復位的位置不是0而是 (-移動到A位置后繼續下拉的距離),這點需要好好注意下。
整個邏輯的過程如下。
三.實現
這里我用的下拉回彈是在網上找到的一個pullscrollview,我做了些小修改(不過不可否認的是這個pullscrollview是有小bug的,這里為了演示就將就了,大家可以換成自己喜歡的下拉刷新庫)
簡要說下pullscrollview大致思路:
主要方法是doActionMove(MotionEvent event)
if (deltaY * 0.5f * SCROLL_RATIO > getResources().getDimension(R.dimen.jellyball_pullmax)) {
//LogUtil.m("State.REFRESH");
mState = State.REFRESH;
}
...
...
if (isMoving) {
...
...
mContentView.layout(mContentRect.left, top, mContentRect.right, bottom);
// 移動header view
mHeader.layout(mHeader.getLeft(), mCurrentTop, mHeader.getRight(), mCurrentBottom);
...
...
}
代碼中都有注釋,很好理解,不再解釋,大家自己下載代碼看即可。 這里說明下,在pullscrollview中我定義了三個接口
public interface OnTurnListener {
//下拉時回調
public void onPull(float y);
//復位時回調
public void onUp(float y);
//開始刷新時回調
public void onRefresh();
}
正是這三個接口傳遞出的 y 讓jellyball能根據滑動的距離做出相應的操作,實現jellyball與任一下拉刷新庫的解耦。
———————————–此處是分割線——————————————-
下面就是今天的主角—-jellyball 了!
首先是一大堆的變量
然后進行基本初始化得到變量需要的數據
下面我們主要來看看setPullHeight、setUpHeight這兩個函數
圖片中的代碼都有注釋了,這里就不再描述了(個人感覺圖片的展示效果比貼代碼的效果更好看,所以代碼基本都是貼圖片的`(∩_∩)′)
setPullHeight方法
setUpHeight方法
ondraw繪圖方法
從上述代碼中可以看出連接setPullHeight、setUpHeight與ondraw方法的橋梁就是
setType方法,每次設置后都會進行invalidate();進行一次ondraw重繪操作
下面再來看看setType中的startRebounceAnim方法
之所以這里用了動畫,主要了想利用applyTransformation方法,該方法會自動計算setDuration中設定的時間此刻的時間流逝比,這樣就省去了我們自己去計算的麻煩(當然,你如果不喜歡這種方法,你也可以自己寫個定時器,自己計算時間流逝比)
得到rebounceInterpolatedTime后,我們的回彈方法在ondraw方法中的rebounceAction方法中用到。
該方法又會調用一系列這些方法
這些方法顧名思義可知是為了根據時間流逝比得到回彈的距離。 那么問題來了,怎么樣讓一個回彈距離是從大到小最后逐漸變為0呢?
正弦、余弦函數?NO!看看函數圖像就知道,并不會從大到小的變化(雖然最后會變成0) 那么答案是什么呢? 我的答案是
簡諧振動函數(我怎么知道的呢?百度….) 地址就是
http://www.jcodecraeer.com/IOS/2015/0614/3038.html 大家可以去學習下。
這里我貼出主要方法
其中式子中的 5 相當于阻尼系數,數值越小幅度越大;式子中的 30 相當于震蕩頻率 ,數值越大震蕩次數越多。
大家可以到這里實時根據函數看出圖像https://www.desmos.com/calculator
我用到的函數算式是 ((1 - Math.exp(-2 * (x + 0.052)) * Math.cos(20 * (x +
0.052))) - 1) * rebounceX / 3 * 2 之所以x需要+0.052是因為我測試算式時在這個https://www.desmos.com/calculator網站上看到當x=0.052時,算式得到的值才是0,若x=0,則算式值不是0(也就是我們其實的時候算式值有偏移量,這并不是我們想要的。)
而之所以是x+0.052,不是x-0.052,我想這得問你的高中數學老師了::>_<::截圖,寫代碼寫了一大串,終于算是擼出來我們想要的效果了!給自己一個贊!?
四.使用方法
使用方法也超級簡單,三行代碼輕松搞定。(因為我把邏輯操作全部封裝到了jellyball中,大家可以輕松使用到自己的下拉刷新庫中了,只需要獲取且暴露出自己下拉刷新庫下拉和復位和刷新時的接口即可!)
在Mainacitivty中
五.代碼下載
代碼可能會有點點亂糟糟,下一次我再把path刷新時的小球刷新的效果做出來再更新一遍代碼好了。
代碼下載地址:https://github.com/ImmortalZ/jellyball
如果大家覺得不錯,希望大家可以star、fork下,算是對我的鼓勵吧,先謝謝啦`(∩_∩)′
有問題也歡迎大家評論,希望大家能不吝賜教,讓小弟成長起來!
來源:http://blog.csdn.net/mr_immortalz/article/details/51137319