日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android下拉刷新开源库对比(转)

發布時間:2025/4/16 Android 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android下拉刷新开源库对比(转) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

安卓下拉刷新開源庫對比

作者:desmond1121?

目前僅比對github上star數>1500的下拉刷新開源庫,在比較完成之后可能會加入其它有代表性的庫.

Repo

RepoOwnerStar (2015.12.5)versionSnap shot
Android-PullToRefresh?(作者已停止維護)chrisbanes6014latest
android-Ultra-Pull-To-Refreshliaohuqiu34131.0.11
android-pulltorefresh?(作者已停止維護)johannilsson2414latest
PhoenixYalantis18971.2.3
FlyRefreshrace60418432.0.0
SwipeRefreshLayoutAndroid Support v4 (19.1.0 ↑)Nonelatest

拓展性

Repo自定義頂部視圖支持的內容布局
Android-PullToRefresh不支持,只能改代碼。 由于僅支持其中實現的LoadingLayout作為頂視圖,改代碼實現自定義工作量較大。任意視圖,內置:GridViewListView,HorizontalScrollViewScrollView?,WebView
android-Ultra-Pull-To-Refresh任意視圖。 通過繼承PtrUIHandler并調用PtrFrameLayout.addPtrUIHandler()得到最大支持。任意視圖
android-pulltorefresh不支持,只能改代碼。 代碼僅一個ListView,耦合度太高,改動工作量較大。無法擴展,自身為ListView
Phoenix不支持,此控件特點就是頂部視圖及動畫。任意視圖,只顯示最后一個嵌套的子視圖。
FlyRefresh不支持,此控件特點就是頂部視圖及動畫。任意視圖
SwipeRefreshLayout不支持,固定為Material風格任意視圖

易用性

Repo可在gradle配置上拉加載自動加載滑動阻尼配置
Android-PullToRefresh××移動比固定1/2
android-Ultra-Pull-To-Refresh×
android-pulltorefresh×××移動比固定1/1.7
Phoenix××移動比固定1/2
FlyRefresh×××
SwipeRefreshLayout××移動比固定1/2

觸屏事件分發

本節分析控件對于觸屏事件的分發以及處理拖動的時機,具體拖動實現將在下一節中介紹。 此處添加進一個可以橫滑的組件,并將所有組件中的ListView替換為自己實現的ClassicListView,重寫控件dispatchTouchEvent,?onTouchEvent來觀察事件的處理傳遞。

1. Chris Banes’ ptr

觸屏分發:

  • dispatchTouchEvent?沒有處理。

  • onInterceptTouchEvent

    • DOWN?不攔截。若可以拉動,更新拉動狀態(mIsBeingDragged)為false;

    • MOVE?正在更新、被拉動狀態下都會攔截(返回true);

    • UP/CANCEL?不攔截,更新被拉動狀態為false。

  • onTouchEvent?(此階段處理UI拖動邏輯)

    • DOWN?此時可以拉動刷新時消耗該event(返回true),否則返回false;

    • MOVE?被拉動時消耗該event(返回true),否則返回false;

    • UP/CANCEL?被拉動時,消耗該event(返回true),否則返回false。

分析: 在onTouchEvent階段處理了UI移動邏輯,且dispatch階段不處理分發邏輯。配合此處intercept的處理,有兩種情況:

  • 事件被下層view消耗了(如正在進行橫滑),則無法進到自身的onTouchEvent階段,就無法進行下拉、上拉的拖動;

  • 在自身進行上拉、下拉拖動時,事件將被截斷,無法分發到下層View。

觸屏事件示例:?

2. Liaohuqiu’s ptr

觸屏分發:

  • dispatchTouchEvent?(此階段處理UI拖動邏輯)

    • DOWN?手動調用super.dispatchTouchEvent()將事件傳遞下去,但之后直接返回true,保證后續能夠處理到move、up、cancel事件;

    • MOVE?被拉動時直接返回true,不向下傳遞事件;沒有被拉動、無法觸發拉動時不處理,傳遞給下層view。若設置了disableWhenHorizontalMove,則在沒有被拉動時的橫滑操作直接傳遞給下層view;

    • UP/CANCEL?如果被拖動了,則直接返回true,截斷了此次事件,并手動向下層傳遞一個cancel事件;否則直接傳遞給下層view。

  • onInterceptTouchEvent?沒有處理

  • onTouchEvent?沒有處理

分析: dispatch階段直接處理了分發邏輯與UI移動邏輯。只要它自身或它的子view處理了事件,dispatch永遠會被觸發,且它down時永遠返回true。那么可以說:只要滿足能夠下拉的情況(對于ListView,默認為第一項完全可見)時,下拉刷新動作一定會被觸發。一旦拉動,會在updatePos里面向下層view傳遞一個cancel事件,下層將會不再處理此次事件序列(原因可見View.dispatchTouchEvent()?->?InputEventConsistencyVerifier.onTouchEvent())。 所以如果內部有沖突的滑動事件處理機制(典型就是嵌套橫滑),那么只要一進行刷新拉動,內部的事件處理馬上就會被截斷。與Chris Banes的下拉刷新處理機制(內部消耗事件時外部無法拉動)不一樣。 觸屏事件示例:?

3.其他庫

基本的做法就是如上兩種,由于ListView一定會消耗事件,如果是嵌套視圖的話必須重寫onInterceptTouchEvent+onTouchEvent或者直接重寫dispatchTouchEvent才能夠保證正確接收并處理到觸摸事件。兩種方法的特點已經在上面分別列出,下面簡單列出余下庫的做法:

  • Johannilsson’s ptr?沒有嵌套,直接處理onTouchEvent;

  • Yalantis’s ptr?嵌套視圖,處理類似Chris banes’ ptr;

  • race604’s ptr?嵌套視圖,處理類似Chris banes’ ptr;

  • SwipeRefreshLayout?嵌套視圖,處理類似Liaohuqiu’s ptr。

性能分析

通過捕捉如下圖中的操作持續1秒鐘的systrace進行性能分析:??> 注:由于開源庫Header大多無法直接放自定義頂部視圖,頭部視圖復雜程度不同,數據對比結果會有所偏差。

1. Chris Banes’s Ptr

滑動實現方式:觸摸造成的下拉均是View.scrollTo()實現的;在松手之后,View.post(Runnable)觸發Runnable執行回滾動畫,在滑回原處之前不斷post自己,并配合Interpolator執行scrollTo()進行滾動。 trace snapshot:??分析: 作為Github上星星數最多的Android下拉刷新控件,從性能上看(渲染時間構成)幾乎沒有什么明顯的缺點??上У氖亲髡咭呀洸辉倬S護,頂部視圖的擴展性比較差,并且gradle中也無法使用。在本次demo這類層級比較簡單的環境中,幾乎都達到了60fps,可以與后面的trace對比。

2. liaohuqiu’s Ptr

滑動實現方式:觸摸造成的下拉均是View.offsetTopAndBottom()實現的;在松手之后,觸發Scroller.startScroll()計算回滾,使用View.post(Runnable)不停地監視Scroller的計算結果,從而實現視圖變化(此處依然是View.offsetTopAndBottom()完成視圖移動)。 trace snapshot:?分析: 這套開源庫可以說是自定義功能最強的組件了,你可以實現PtrUIHandler并將其add到PtrFrameLayout完美地與下拉刷新事件適配。美中不足的就是在下拉狀態變化的時候會有一陣measure時間。我查看了一下代碼,發現是PtrClassicFrameLayout(作者實現的集成默認下拉視圖的layout)的頂部視圖出了問題:??看!都是wrap_content,那么當里面的內容變化的時候,是會觸發View.requestLayout()的。不要小看這一個子視圖的小操作,一個requestLayout()大概是這么一個流程:View.requestLayout()->ViewParent.requestLayout()->…->ViewRootImpl.requestLayout()->ViewRootImpl.doTraversal()=>MEASURE(ViewGroup)=>MEASURE(ChildView of ViewGroup) 在層級復雜的時候(大部分互聯網產品由于復雜的產品需求嵌套都會比較多),它會層層向上調用,將measure時間放大至一個可觀的層級。下拉刷新界面的卡頓由此而來。 我修改了一下,將其全部變為固定高度、寬度,之后的trace如下:??measure時間神奇的沒掉了吧:)

3. johannilsson’s Ptr

滑動實現方式:初始時setSelection(1)隱藏頂部視圖(使用這個下拉刷新控件注意將滾動欄隱藏,否則會露餡)。在拉下來超過header view的measure高度之前,均是ListView自有的滾動;在下拉超過header measure高度之后,對header使用View.setPadding()讓header繼續下移。 trace snapshot:??分析: 通過頂視圖調用View.setPadding()來實現的滑動,在下拉距離超過header高度后,會造成不斷的requestLayout()!這就解釋了為什么圖中UI線程的藍色塊時間(measure時間)很明顯。當你在視圖層級比較復雜的app中使用它時,下拉動作所造成的開銷會非常明顯,卡頓是必然結果。

4. Yalantis’s Ptr

滑動實現方式:通過View.topAndBottomOffset()移動視圖,在松手之后啟動一個Animation執行回滾動畫,內容視圖的移動也使用View.offsetTopAndBottom()實現。為了保證子內容視圖的底部padding在移動之后與布局文件中的padding屬性一致,它額外調用了View.setPadding()實時設置padding。 頂部動效實現方式:Drawabledraw()中,為Canvas中設置“太陽”偏移量及背景縮放。 trace snapshot:??分析: 此開源庫動畫效果非常柔和,且頂部視圖全部是通過draw去更新,不會造成第三個開源庫那樣的大開銷問題。可惜的是比較難以去自定義頂部視圖,不好在線上產品中使用,不過這個開源庫是一個好的練手與學習的對象。由于頂部動效實現開銷不大,它的性能同樣非常好。 它在松手后回滾時調用的View.setPadding()可能會造成measure開銷比較大,于是我特地測了一下松手回滾的trace,一看確實measure時間非常可觀:??確實它如果要保證展示內容視圖的padding與布局文件中一致,是必須這么做的(調用View.setPadding()),因為通過View.offsetTopAndBottom()向下移動子視圖時,子視圖的內容整個移動下來,在視覺上會影響它設置好的底部padding。但是很有意思,它向下移動的時候沒有這么設置,拉下來的時候底部padding就沒了。回滾動畫的時候才設了padding,就顯得沒那么必要了。我在demo中也進行了實踐,確實是這樣的:??我暫時也沒想到什么方法可以更好地處理子視圖padding問題。但實際上,由于這個庫是一個嵌套視圖,并且只會有一個內容視圖顯示出來,可以嘗試放棄對子視圖padding的處理。如果需要,可以使用父視圖的padding來代替,這樣是最完美的效果。子視圖再怎么移動,也會被父視圖已經設好的padding局限住。由此一來padding就不會被影響,同時提高了性能。不過這樣一來犧牲了子視圖padding的設置,在使用的時候可以根據需要各取所需。 我粗略的做了一點點改動,將它的setPadding()注釋掉了。不過由于該庫的一些其他實現邏輯,導致會有一些問題,此處僅看性能上的變化,改動后松手回滾trace,已經沒有了measure時間:

5. race604’s Ptr

滑動實現方式:View.topAndBottomOffset()?頂部動效實現方式:

  • 飛機滑動?ObjectAnimator.

  • 山體移動、樹木彎曲?通過移動距離計算山體偏移、樹木輪廓,得出Path后進行draw.

trace snapshot:??分析:每次拖動都會重新計算背景”山體”與”樹木”的Path,造成了draw時間過長。效果不錯,也是一個好的學習對象,相比Yalantis的下拉刷新性能上就差一些了,它的draw中的計算量太多。使用起來疑似有bug:拖動到頂部,無法再往上拖動,并且會出現拖動異常。

6. SwipeRefreshLayout

滑動實現方式:內容固定,僅有頂部動效。 頂部動效實現方式:

  • 上下移動?View.bringToFront()?+?View.offsetTopAndBottom().

  • 動效?通過移動偏移量計算弧形曲線的角度、三角形的位置,使用drawArc,?drawTriangle將他們畫到Canvas上。

trace snapshot:??分析:官方的下拉刷新組件,動畫十分美觀簡潔,API構造清晰明了。但是為什么每次的移動都會有一段明顯的measure時間呢?我研究了一下代碼,發現罪魁禍首是View.bringToFront(),它在每一次滑動的時候都會對頂部動效視圖調用這個函數。仔細追朔這個函數源碼,它會走到下面這段代碼中:?ViewGroup.java

1

2

3

4

5

6

7

8

9

10

11

????public?void?bringChildToFront(View?child)?{

????????final?int?index?=?indexOfChild(child);

????????if?(index?>=?0)?{

????????????removeFromArray(index);

????????????addInArray(child,?mChildrenCount);

????????????child.mParent?=?this;

????????????requestLayout();

????????????invalidate();

????????}

????}

看,它是會觸發View.requestLayout()的!這個函數會造成的后果我們在之前已經解釋了,它會造成大量的UI線程開銷。實際上我認為這個函數是沒有調用的必要的,SwipeRefreshLayout明明在重寫onLayout()的時候,header會被layout到child之上,沒有必要再bringToFront()。 于是我copy了一份代碼,將這一行注了(對應代碼ptr-source-lib/src/main/java/com/android/support/SwipeRefreshLayout.java),再次編譯,measure時間確實沒掉了,對功能毫無影響,性能卻有了很大優化:??這樣一來就不會每一次拉動,都會觸發measure。若有同學知道這個bringToFront()在其中有其他我未探測到的功效,請issue指點:)

總結

Repo性能拓展性綜合建議
Android-PullToRefresh★★★★★★★★由于作者不再維護,無法在gradle中配置,頂部視圖難以拓展,不建議放入工程中使用
android-Ultra-Pull-To-Refresh★★★★★★★★★★如之前分析,PtrClassicFrameLayout性能有缺陷;建議使用PtrFrameLayout,性能較好。這套庫自定義能力很強,建議使用。
android-pulltorefresh實現方式上有缺陷,拓展性也很差。優點就是代碼非常簡單,只能作為反面例子。
Phoenix★★★★★★效果非常好,性能不錯,可惜比較難拓展頂部視圖,為了適配布局padding造成了性能損失,有優化空間??梢宰鳛閷W習與練手的對象。
FlyRefresh★★★★★★效果很新穎,可惜的是頂部視圖計算動效上開銷太大,優化空間較少,可以作為學習與練手的對象。
SwipeRefreshLayout★★★★★官方出品,更新有保障,但是如上分析,其實性能上還是有點缺陷的,拓展性比較差,不建議放入工程中使用。

本例中用到的代碼可以到github上找到。


轉載于:https://blog.51cto.com/4397014/2163347

總結

以上是生活随笔為你收集整理的Android下拉刷新开源库对比(转)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。