1. 程式人生 > >RecyclerView 判斷滑到底/頂部的方法

RecyclerView 判斷滑到底/頂部的方法

mode sbo style osi set vertica 條件 pos cif

判斷RecyclerView到達底部的幾種方法

項目中的案例

  1. mRvChat.addOnScrollListener(new RecyclerView.OnScrollListener() {
  2. private int minLeftItemCount=10;//剩余多少條時開始加載更多
  3. @Override
  4. public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
  5. if (recyclerView.getLayoutManager() instanceof LinearLayoutManager) {
  6. LinearLayoutManager
    layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
  7. int itemCount = layoutManager.getItemCount();
  8. int lastPosition = layoutManager.findLastCompletelyVisibleItemPosition();
  9. XLog.tag("bqt3").i("【總數】" + itemCount + "【位置】" + lastPosition);
  10. if (lastPosition == layoutManager.getItemCount
    () - 1) {//容錯處理,保證滑到最後一條時一定可以加載更多
  11. this.onLoadMore();
  12. } else {
  13. if (itemCount > minLeftItemCount) {
  14. if (lastPosition == itemCount - minLeftItemCount) {
  15. //一定要意識到,onScrolled方法並不是一直被回調的,估計最多一秒鐘幾十次
  16. //所以當此條件滿足時,可能並沒有回調onScrolled方法,也就不會調用onLoadMore方法
  17. //所以一定要想辦法彌補這隱藏的bug,最簡單的方式就是當滑到最後一條時一定可以加載更多
  18. this.onLoadMore();
  19. }
  20. } else {//(第一次進入時)如果總數特別少,直接加載更多
  21. this.onLoadMore();
  22. }
  23. }
  24. }
  25. }
  26. private void onLoadMore() {
  27. if (canLoadMore) {
  28. canLoadMore = false;
  29. ChatReqHelper.requestGroupHis(groupId, ((ChatModel) mGroupChats.get(mGroupChats.size() - 1)).getMsgId());
  30. XLog.tag("bqt3").i("【加載更多數據】");
  31. }
  32. }
  33. });

利用 lastVisibleItemPosition 判斷

簡單判斷
  1. public static boolean isVisBottom(RecyclerView recyclerView){
  2. LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
  3. int lastVisibleItemPosition = layoutManager.findLastVisibleItemPosition(); //屏幕中最後一個可見子項的position
  4. int visibleItemCount = layoutManager.getChildCount(); //當前屏幕所看到的子項個數
  5. int totalItemCount = layoutManager.getItemCount(); //當前RecyclerView的所有子項個數
  6. int state = recyclerView.getScrollState(); //RecyclerView的滑動狀態
  7. if(visibleItemCount > 0 && lastVisibleItemPosition == totalItemCount - 1 && state == recyclerView.SCROLL_STATE_IDLE){
  8. return true;
  9. }else {
  10. return false;
  11. }
  12. }
當屏幕中最後一個子項 lastVisibleItemPosition 等於所有子項個數 totalItemCount - 1,那麽RecyclerView就到達了底部。但是,如果 totalItemCount 等於1,並且這個item的高度比屏幕還要高時,我們可以發現這個item沒完全顯示出來就已經被判斷為拉到底部。

利用 computeVerticalScrollRange 等判斷

這種方法原理其實很簡單,而且也是View自帶的方法
  1. public static boolean isSlideToBottom(RecyclerView recyclerView) {
  2. return recyclerView != null
  3. && recyclerView.computeVerticalScrollExtent()//當前屏幕顯示區域的高度
  4. + recyclerView.computeVerticalScrollOffset()//當前屏幕之前滑過的距離
  5. >= recyclerView.computeVerticalScrollRange();//整個View控件的高度
  6. }
這種方法經過測試,暫時還沒發現有bug,而且它用的是View自帶的方法,所以個人覺得比較靠譜。

利用 canScrollVertically(direction) 判斷

這種方法更簡單,就通過簡單的調用方法,就可以得到你想要的結果。這種方法與第二種方法其實是同一種方法,我們看看 canScrollVertically 的源碼:
  1. /**
  2. * Check if this view can be scrolled vertically in a certain direction.
  3. *
  4. * @param direction Negative to check scrolling up, positive to check scrolling down.
  5. * @return true if this view can be scrolled in the specified direction, false otherwise.
  6. */
  7. public boolean canScrollVertically(int direction) {
  8. final int offset = computeVerticalScrollOffset();
  9. final int range = computeVerticalScrollRange() - computeVerticalScrollExtent();
  10. if (range == 0) return false;
  11. if (direction < 0) {
  12. return offset > 0;
  13. } else {
  14. return offset < range - 1;
  15. }
  16. }
canScrollVertically(1)的值表示是否能向上滾動,true表示能滾動,false表示已經滾動到底部canScrollVertically(-1)的值表示是否能向下滾動,true表示能滾動,false表示已經滾動到頂部

利用 LinearLayoutManager 來判斷

這種方法其實是比較呆板的,就是利用LinearLayoutManager的幾個方法算出已經滑過的子項的距離、屏幕的高度、RecyclerView的總高度,最後將高度作比較。
算出一個子項的高度
  1. public static int getItemHeight(RecyclerView recyclerView) {
  2. int itemHeight = 0;
  3. View child = null;
  4. LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
  5. int firstPos = layoutManager.findFirstCompletelyVisibleItemPosition();
  6. int lastPos = layoutManager.findLastCompletelyVisibleItemPosition();
  7. child = layoutManager.findViewByPosition(lastPos);
  8. if (child != null) {
  9. RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
  10. itemHeight = child.getHeight() + params.topMargin + params.bottomMargin;
  11. }
  12. return itemHeight;
  13. }
算出滑過的子項的總距離
  1. public static int getLinearTotalHeight(RecyclerView recyclerView) {
  2. int totalHeight = 0;
  3. LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
  4. View child = layoutManager.findViewByPosition(layoutManager.findFirstVisibleItemPosition());
  5. int headerCildHeight = getHeaderHeight(recyclerView);
  6. if (child != null) {
  7. int itemHeight = getItemHeight(recyclerView);
  8. int childCount = layoutManager.getItemCount();
  9. totalHeight = headerCildHeight + (childCount - 1) * itemHeight;
  10. }
  11. return totalHeight;
  12. }
算出所有子項的總高度
  1. public static boolean isLinearBottom(RecyclerView recyclerView) {
  2. boolean isBottom = true;
  3. int scrollY = getLinearScrollY(recyclerView);
  4. int totalHeight = getLinearTotalHeight(recyclerView);
  5. int height = recyclerView.getHeight();
  6. // Log.e("height","scrollY " + scrollY + " totalHeight " + totalHeight + " recyclerHeight " + height);
  7. if (scrollY + height < totalHeight) {
  8. isBottom = false;
  9. }
  10. return isBottom;
  11. }
其他
  1. public static int getHeaderHeight(RecyclerView recyclerView) {
  2. int headerCildHeight = 0;
  3. LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
  4. int firstHeaderPos = layoutManager.findFirstCompletelyVisibleItemPosition();
  5. View headerCild = layoutManager.findViewByPosition(firstHeaderPos);
  6. if (headerCild != null) {
  7. RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) headerCild.getLayoutParams();
  8. headerCildHeight = headerCild.getHeight() + params.topMargin + params.bottomMargin;
  9. }
  10. return headerCildHeight;
  11. }
  12. public static int getLinearScrollY(RecyclerView recyclerView) {
  13. int scrollY = 0;
  14. LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
  15. int headerCildHeight = getHeaderHeight(recyclerView);
  16. int firstPos = layoutManager.findFirstVisibleItemPosition();
  17. View child = layoutManager.findViewByPosition(firstPos);
  18. int itemHeight = getItemHeight(recyclerView);
  19. if (child != null) {
  20. int firstItemBottom = layoutManager.getDecoratedBottom(child);
  21. scrollY = headerCildHeight + itemHeight * firstPos - firstItemBottom;
  22. if (scrollY < 0) {
  23. scrollY = 0;
  24. }
  25. }
  26. return scrollY;
  27. }

雖然這種方法看上去比較呆板的同時考慮不很周全,但這種方法可以對RecylerView的LinearLayoutManager有深一步的理解!

null

RecyclerView 判斷滑到底/頂部的方法