Judgment of RecyclerView pulling up to load more and scrolling to the bottom (top)

There are many examples on the Internet about pull-down refresh and pull-up loading. Pull-down refresh is relatively simple and you can directly use the SwipeRefreshLayout provided by the system. The more troublesome thing is that there are more pull-up loads. one time.

demand analysis

After the RecyclerView scrolls to the bottom, when the user drags up (here, the usage scenario is dragging, rather than automatically scrolling to the bottom after the finger is off the screen), the RecyclerView shows that more words are loaded and more data is requested. Update RecyclerView after success; by default, the height of RecyclerView is greater than the height that can be displayed, that is, RecyclerView does not display all items and can be slid, otherwise it means that there is no need to load more.

technical point

  • Judging that RecyclerView has scrolled to the bottom
  • Judge RecyclerView drag and drop

Judging that RecyclerView has scrolled to the bottom

Judging whether the RecyclerView has reached the bottom or not, there are several methods circulating on the Internet. These methods have some problems, and finally we will give a recommended method.

1. Determine whether to reach the bottom according to the item
This method is the most common, and it is generally implemented as follows:

public static boolean isVisBottom(RecyclerView recyclerView){  
  LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();  
  //屏幕中最后一个可见子项的position
  int 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;  
  }
}

When judging whether to scroll to the bottom in this way, as long as the last item shows a little bit, it will trigger to load more, and the user cannot see the words "load more" at the FooterView at this time (the same as dragging and dropping to show load more Requirements do not match); In addition, when the items of RecyclerView are too few to fill the entire RecyclerView, it will also trigger loading more; therefore, this method does not meet our requirements.

2. Use canScrollVertically(int direction) to judge whether to reach the bottom

RecyclerView.canScrollVertically(1)的值表示是否能向上滚动,false表示已经滚动到底部
RecyclerView.canScrollVertically(-1)的值表示是否能向下滚动,false表示已经滚动到顶部

This method seems simple, but in fact there are also some pitfalls. When the items of RecyclerView are too few to fill the entire RecyclerView, no matter whether it is pulled up or pulled down, more loading will be triggered; in addition, the direction can not only take 1 and -1, but only need to ensure positive and negative to achieve the same effect.

// View#canScrollVertically(int direction) 源码
public boolean canScrollVertically(int direction) {
    final int offset = computeVerticalScrollOffset();
    final int range = computeVerticalScrollRange() - computeVerticalScrollExtent();
    if (range == 0) return false;
    if (direction < 0) {
        return offset > 0;
    } else {
        return offset < range - 1;
    }
}

3. Perform a series of calculations through LinearLayoutManager
This method is not recommended, the process is very complicated, but it is very helpful for understanding the layout of View. This method is divided into four steps, and the online method is copied as follows (readers are asked to verify whether the same problems as methods 1 and 2 also exist):

  • Calculate the height of a child

    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;
    }

  • Calculate the total distance of the slid children

    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;
    }

  • Calculate the total height of all children

    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;
    }

  • height for comparison

    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;
    }

Judge RecyclerView drag and drop

This step is relatively simple, just monitor the scrolling directly.

RecyclerView.addOnScrollListener(new OnScrollListener() {
        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            super.onScrollStateChanged(recyclerView, newState);
            if (newState == SCROLL_STATE_DRAGGING) {
                // 拖拽状态,实际使用中还需要判断 加载更多 是否已显示
            }
        }

        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            super.onScrolled(recyclerView, dx, dy);
        }
    });

recommended method

On the basis of View#canScrollVertically(int direction), this method is optimized for the scenario of pulling up and dragging and the items may not fill the entire RecyclerView. The code is as follows:

RecyclerView.addOnScrollListener(new OnScrollListener() {
        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            super.onScrollStateChanged(recyclerView, newState);
            if (newState == SCROLL_STATE_DRAGGING && 没有触发加载更多) {
                if (RecyclerView.computeVerticalScrollOffset() > 0) {// 有滚动距离,说明可以加载更多,解决了 items 不能充满 RecyclerView 
                的问题及滑动方向问题
                    boolean isBottom = false ;
                    isBottom = RecyclerView.computeVerticalScrollExtent()
                        + RecyclerView.computeVerticalScrollOffset()
                        == RecyclerView.computeVerticalScrollRange() ;
                    // 也可以使用 方法2
                    // isBottom = !RecyclerView.canScrollVertically(1) ;
                    if (isBottom) {
                        // 说明滚动到底部,触发加载更多
                        ...
                    }
                }
            }
        }

        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            super.onScrolled(recyclerView, dx, dy);
        }
    });

At this point, the processing of the pull-up judgment is completed, and the next article will deal with the display of loading more views.

Attached is a schematic diagram found on the Internet:

Write picture description here

Supongo que te gusta

Origin blog.csdn.net/niuzhucedenglu/article/details/72842061
Recomendado
Clasificación