总结和分析几种判断RecyclerView到达底部的方法
上一篇文章我講到用事件分發的原理結合SwipeRefreshLayout寫一個RecyclerView的上下拉,里面有一個判斷RecyclerView是否到達底部的方法isBottom。我的同事用了這個上下拉之后發現有些小bug,沒考慮周全,譬如各個子項高度不統一的時候,然后我找到原因是因為這個判斷上下拉的問題。所以,我就去網上查到幾種判斷RecyclerView到達底部的方法,發現各有千秋。以下的分析都以上一篇文章的SwipeRecyclerView為例。
1.lastVisibleItemPosition == totalItemCount - 1判斷; 2.computeVerticalScrollRange()等三個方法判斷; 3.canScrollVertically(1)判斷; 4.利用RecyclerView的LinearLayoutManager幾個方法判斷。其實,第2和第3種是屬于同一種方法,在下面的分析會講到。
一、首先,我們來介紹和分析一下第一種方法,也是網上最多人用的方法:
public static boolean isVisBottom(RecyclerView recyclerView){ LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager(); //屏幕中最后一個可見子項的positionint lastVisibleItemPosition = layoutManager.findLastVisibleItemPosition(); //當前屏幕所看到的子項個數int visibleItemCount = layoutManager.getChildCount(); //當前RecyclerView的所有子項個數int totalItemCount = layoutManager.getItemCount(); //RecyclerView的滑動狀態int state = recyclerView.getScrollState(); if(visibleItemCount > 0 && lastVisibleItemPosition == totalItemCount - 1 && state == recyclerView.SCROLL_STATE_IDLE){ return true; }else { return false; } }很明顯,當屏幕中最后一個子項lastVisibleItemPosition等于所有子項個數totalItemCount - 1,那么RecyclerView就到達了底部。但是,我在這種方法中發現了極為極端的情況,就是當totalItemCount等于1,而這個子項的高度比屏幕還要高。
item_recycleview.png看看效果圖:
效果圖.png我們可以發現這個子項沒完全顯示出來就已經被判斷為拉到底部。當然,這種方法一般情況下都能滿足開發者的需求,只是遇到了強迫癥的我~
二、下面我們介紹第二種方法:
public static boolean isSlideToBottom(RecyclerView recyclerView) { if (recyclerView == null) return false; if (recyclerView.computeVerticalScrollExtent() + recyclerView.computeVerticalScrollOffset() >= recyclerView.computeVerticalScrollRange()) return true; return false; }這種方法原理其實很簡單,而且也是View自帶的方法。
原理圖.png這樣就很清晰明了,computeVerticalScrollExtent()是當前屏幕顯示的區域高度,computeVerticalScrollOffset() 是當前屏幕之前滑過的距離,而computeVerticalScrollRange()是整個View控件的高度。
這種方法經過測試,暫時還沒發現有bug,而且它用的是View自帶的方法,所以個人覺得比較靠譜。
三、下面講講第三種方法:
RecyclerView.canScrollVertically(1)的值表示是否能向上滾動,false表示已經滾動到底部 RecyclerView.canScrollVertically(-1)的值表示是否能向下滾動,false表示已經滾動到頂部這種方法更簡單,就通過簡單的調用方法,就可以得到你想要的結果。我一講過這種方法與第二種方法其實是同一種方法,那下面來分析一下,看看canScrollVertically的源碼:
canScrollVertically的源碼是不是一目鳥然了,canScrollVertically方法的實現實際上運用到的是方法二的三個函數,只是這個方法Android已經幫我們封裝好了,原理一模一樣的。
本人現在也是運用了這種方法做判斷的懶人工具類都省了~
四、最后一種方法其實是比較呆板的,就是利用LinearLayoutManager的幾個方法,1.算出已經滑過的子項的距離,2.算出屏幕的高度,3.算出RecyclerView的總高度。然后用他們做比較,原理類似于方法二。
public static int getItemHeight(RecyclerView recyclerView) { int itemHeight = 0; View child = null; LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager(); int firstPos = layoutManager.findFirstCompletelyVisibleItemPosition(); int lastPos = layoutManager.findLastCompletelyVisibleItemPosition(); child = layoutManager.findViewByPosition(lastPos); if (child != null) { RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams(); itemHeight = child.getHeight() + params.topMargin + params.bottomMargin; } return itemHeight;}算出一個子項的高度
public static int getLinearScrollY(RecyclerView recyclerView) { int scrollY = 0; LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager(); int headerCildHeight = getHeaderHeight(recyclerView); int firstPos = layoutManager.findFirstVisibleItemPosition(); View child = layoutManager.findViewByPosition(firstPos); int itemHeight = getItemHeight(recyclerView); if (child != null) { int firstItemBottom = layoutManager.getDecoratedBottom(child); scrollY = headerCildHeight + itemHeight * firstPos - firstItemBottom; if(scrollY < 0){ scrollY = 0; } } return scrollY; }算出滑過的子項的總距離
public static int getLinearTotalHeight(RecyclerView recyclerView) { int totalHeight = 0; LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager(); View child = layoutManager.findViewByPosition(layoutManager.findFirstVisibleItemPosition()); int headerCildHeight = getHeaderHeight(recyclerView); if (child != null) { int itemHeight = getItemHeight(recyclerView); int childCount = layoutManager.getItemCount(); totalHeight = headerCildHeight + (childCount - 1) * itemHeight; } return totalHeight; }算出所有子項的總高度
public static boolean isLinearBottom(RecyclerView recyclerView) { boolean isBottom = true; int scrollY = getLinearScrollY(recyclerView); int totalHeight = getLinearTotalHeight(recyclerView); int height = recyclerView.getHeight();// Log.e("height","scrollY " + scrollY + " totalHeight " + totalHeight + " recyclerHeight " + height); if (scrollY + height < totalHeight) { isBottom = false; } return isBottom; }高度作比較
雖然這種方法看上去比較呆板的同時考慮不很周全,但這種方法可以對RecylerView的LinearLayoutManager有深一步的理解,這也是我的師兄給我提供的一個借鑒的類,我非常感謝他!有興趣的同學可以去下載源碼的做進一步的研究,發現有更好玩的方法可以一起研究!
源碼下載鏈接
作者:19snow93
鏈接:https://www.jianshu.com/p/c138055af5d2
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。 創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎
總結
以上是生活随笔為你收集整理的总结和分析几种判断RecyclerView到达底部的方法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 项目接入实现复杂布局的vlayout
- 下一篇: 无线网络间歇性卡顿是什么原因