Android 改造SwipeRefreshLayout 支持上拉加載

原文鏈接 : http://mp.weixin.qq.com/s?__biz=MzAxMTI4MTkwNQ==&mid=2650822399&idx=1&sn=9cc9c74d063cc00c6820bdfefc6bf518&chksm=80b78261b7c00b7799577b10a42f598249b02d3bc1d22f281be0391807d103477ccaad9dfc82&mpshare=1&scene=23&srcid=0323qkEeDyK3MOkfXs3LaNYh%23rd

請支持原文作者 : 鴻洋

看到這個文章我才想起來,今天推薦一個項目,是我的一位好朋友之前在創(chuàng)業(yè)公司的一個項目,后來項目失敗了,經(jīng)允許后將源碼分享出來了,該項目也對SwipeRefreshLayout進行了擴展,支持了上拉,如果有實際需求,不妨也試下這個(項目質(zhì)量非常高)。

https://github.com/pinguo-sunjianfei/Android-Application-ZJB

ps:該項目服務端已經(jīng)停了,所以只能看代碼了,運行不起來了~~

本文作者

本文由Get_Zoom投稿。
Get_Zoom的博客地址:
http://blog.csdn.net/Get_Zoom

1

NestedScrolling機制

之前筆者在設計的時候,想在ViewPager的頁面上實現(xiàn)仿微信的左滑刪除,但是怎么都實現(xiàn)不了,因為其中跟ViewPager的滑動沖突了,當時才疏學淺(現(xiàn)在也是),進了很多坑,比如滑動的攔截、滑動事件在Down之后會跳過判斷等,在沒有系統(tǒng)學習過這方面知識的情況下以大敗告終。

所以,谷歌人性化地推出了這個機制,滑動之前和父控件商量一下,一切多么融洽,和之前盲人摸象的方式相比人性化多了。

(1)滑動流程

子view獲取到點擊事件后,詢問父親是否需要配合滑動,然后每一次滑動之前都會詢問父親,并記錄下父親消耗的滑動距離,在上面完成后才進行自己自身的滑動。

(2)接口

NestedScrollingChild

NestedScrollingParent

(3)幫助類

NestedScrollingChildHelper NestedScrollingParentHelper

故名思義,上面的幫助類幫助我們處理了上面父子接口的方法。

它們幫助我們實現(xiàn)了邏輯上的方法,在一些情況下我們只希望處理子接口或者父接口,為了對接可以在另一個接口使用幫助類(比如下面的實例,改造SwipeRefreshLayout,我們更希望作為父親處理子view事件而滑動自身,對于上層組件(父)不是很關心,就可以使用NestedScrollingParentHelper來方便編程。

借用網(wǎng)上的一張圖,可以看到兩個接口之間的對應關系:

圖片來源:https://segmentfault.com/a/119000000287365

2

實例演示:改造SwipeRefreshLayout

(1)目的
SwipeRefreshLayout就是一個實現(xiàn)了NestedScrolling機制的控件,可以方便的實現(xiàn)下拉刷新。

現(xiàn)在我們想加上上拉刷新功能,可以反著做,給下方加一個可拉動的控件(小圓圈),然后處理它的滑動事件。為了能兼顧上層,我們再外面還加了常規(guī)的CoordinatorLayout和AppBarLayout作為測試。

成果:


(2)準備工作
改造之前當然要先把人家之前的成果準備好。



首先當然是把我們的SwipeRefreshLayout移過來,可以換一個名字避免以后的沖突。

然后布局中要用到兩個控件,一個是CircleImageView,也就是顯示的小圓圈,附帶陰影功能;一個是MaterialProgressDrawable,用于在CircleImageView顯示進程(顏色滑動)。

在移動的時候SwipeRefreshLayout會報錯,報錯時把東西移動過來就行了。
然后閱讀源碼,我們暫時只處理NestedScrolling機制,所以一般的移動流程比如onTouchEvent可以先放著,以后為了和其他不帶NestedScrolling控件兼容的時候再改進。

(3)開始改造工作
**1.參數(shù)測量 **
一個主要的問題就是,我們下面的圓圈(加載圈,以下簡稱圓圈)要放在哪?

原生的直接放在中間然后上去一個圓圈身位的地方,所以下面圓圈水平位置一樣,豎直的話就放在屏幕下方。

綜合測試出這樣的距離比較好:

所以相應的位置放置我們就這樣:

2.作為父控件配合滑動


a.是否配合滑動

這里我們只增加了一個上拉刷新標志位

這里也是,只是增加了mTotalUnconsumedBottom ,這是我們上拉刷新的未消費路程。

b.滑動之前

我們可以看到源碼中的onNestedPreScroll有這么一段處理:

在滑動前先判斷,我們未消費滑動路程是否還有,有則判斷方向,如果是滑動的反方向,也就是我們再下拉刷新一半的時候又往回拉,這時做出處理,選擇消費當前滑動路程。

所以我們可以寫出下方的拖動預處理:

這里有個坑要提醒下,一開始筆者自作聰明,覺得consumed參數(shù)應該傳絕對值,導致后來往回滑的時候子控件跑得飛快(可以想想為什么),所以這里消費了負的路程就傳回負的路程,可以看看源碼中NestedScrollingChildHelper的實現(xiàn)。

c.正式滑動

這個反而比較容易,只需要加上判斷當前子控件還能不能往上滑。

滑動處理:

大概解釋一下,我們的滑動時分段的,在mTotalDragDistance滑動之前是線性的,在這之后會做一個加速的處理,最多延伸一個mSpinnerOffsetEnd
在實際的view位置改變中,我們使用的是
setTargetOffsetTopAndBottomForBottom (targetY-mCurrentTargetOffsetBottom, true);

這個方法,里面是采用
ViewCompat.offsetTopAndBottom

來改變view的位置的。

d.結(jié)束滑動

如果手指離開的時候,拖動距離不為零,那么我們要做判斷,做出相應的處理

可以看到主要有兩種處理,以mTotalDragDistance為界限,超過這個滑動距離我們就顯示刷新,沒有的話就動畫回到原點。

**3.作為子控件配合滑動 **
我們知道,AppBarLayout和CoordinatorLayout會配合滑動,子view往上滑的時候會隱藏,如果不做處理,在下端圓圈滑動到一半的時候往回滑會把AppBar又拖出來,消費滑動事件,所以我們選擇攔截,在下部圓圈滑動的時候優(yōu)先處理滑動:

到這里,我們的控件就基本完成了,當然谷歌出版的控件,動畫效果是不能少的,它的美觀也體現(xiàn)在這里,由于基本是能模仿的,所以這里不再多講。這個控件的改造主要麻煩在它的動畫銜接以及滑動處理機制(加速等),剩下的都很好理解,建議大家動手試一試。

項目地址:
https://github.com/SGZoom/DailyWidget/tree/master/widgetpro

文章跟代碼可能包含很多不足之處,歡迎大家?guī)兔χ赋鲥e誤與不足,謝謝~

參考文章:
https://segmentfault.com/a/1190000002873657

http://blog.csdn.net/al4fun/article/details/53888990

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容