RecyclerView滑动检测和滑动位置

RecyclerView的滑动检测

RecyclerView的使用中,有时候我们需要监听列表滚动情况:上滑、下滑、顶部、底部。

RecyclerView的滑动检测可以通过给RecyclerView添加滚动监听来实现:recyclerview.addOnScrollListener(RecyclerView.OnScrollListener) (或recyclerview.setOnScrollListener(RecyclerView.OnScrollListener)

所以我们要看一下RecyclerView.OnScrollListener:

    /**
     * 可添加到 RecyclerView 的滑动监听,用于接收 RecyclerView 的滑动信息。 
     * @see RecyclerView#addOnScrollListener(OnScrollListener)
     */
    public abstract static class OnScrollListener {
    
    
        /**
         *当 RecyclerView的滑动状态改变时回调方法被调用。
         *
         * @param recyclerView
         * @param newState     滚动状态。以下其中一个:
	     * 						RecyclerView.SCROLL_STATE_IDLE
         *                      RecyclerView.SCROLL_STATE_DRAGGING
         *                      RecyclerView.SCROLL_STATE_SETTLING
         */
        public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState){
    
    }

        /**
         * 当 RecyclerView 滚动时,回调方法被调用。这个方法会在滚动完成后被调用。
         * 如果布局计算后可见项发生范围变化(item range changes),也将调用此回调。
         * 这种情况下, dx 和 dy 会为 0.
         *
         * @param recyclerView
         * @param dx 水平(horizontal scroll)滚量(距离)
         * @param dy 竖直(vertical scroll)滚动量
         */
        public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy){
    
    }
    }

我们需要在 onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) 方法中判断滑动方向。

其中dx,dy分别表示 在x方向和y方向滑动的值,这个值有正负。

  • dy > 0 表示 上滑, dy>0 表示下滑

通过这两个参数就可以监听滑动方向了。可以用Log验证。

RecyclerView还有一个方法 canScrollVertically(int direction):direction,负数表示上滑,正数表示下滑。通过判断这个方法的返回值,可知 RecyclerView 滑到顶部还是底部。

public abstract class OnVerticalScrollListener
        extends RecyclerView.OnScrollListener {
    
    

    @Override
    public final void onScrolled(RecyclerView recyclerView, int dx, int dy) {
    
    
		if (!recyclerView.canScrollVertically(-1)) {
    
    
			onScrolledToBottom(); //滑到底部
		} else if (!recyclerView.canScrollVertically(1)) {
    
    
			onScrolledToTop(); //滑到顶部
		} else if (dy > 0) {
    
    
			onScrolledUp();
		} else if (dy < 0) {
    
    
			onScrolledDown();
		}
	}
	
    public void onScrolledUp() {
    
    }

    public void onScrolledDown() {
    
    }

    public void onScrolledToTop() {
    
    }

    public void onScrolledToBottom() {
    
    }
}

RecyclerView的滑动位置

几个方法

LinearLayoutManager

  • findLastVisibleItemPosition() :最后一个可见位置
  • findFirstVisibleItemPosition() :第一个可见位置
  • findLastCompletelyVisibleItemPosition() :最后一个完全可见位置
  • findFirstCompletelyVisibleItemPosition() :第一个完全可见位置

StaggeredGridLayoutManager

  • findFirstVisibleItemPositions(int[]) :返回第一个可见span的items的位置
  • findLastVisibleItemPositions(int[]) :返回最后一个可见span的items的位置
  • findFirstCompletelyVisibleItemPositions(int[]) :返回第一个完全可见span的items的位置
  • findLastCompletelyVisibleItemPositions(int[]) :返回最后一个完全可见span的items的位置

使用:

mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
    
    
    @Override
    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
    
    
        super.onScrolled(recyclerView, dx, dy);
        RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
        if (layoutManager instanceof LinearLayoutManager) {
    
    
            int lastVisibleItemPosition = ((LinearLayoutManager) layoutManager).findLastVisibleItemPosition();
            int firstVisibleItemPosition = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition();
            int firstCompletelyVisibleItemPosition = ((LinearLayoutManager) layoutManager).findFirstCompletelyVisibleItemPosition();
            int lastCompletelyVisibleItemPosition = ((LinearLayoutManager) layoutManager).findLastCompletelyVisibleItemPosition();
        } else if (layoutManager instanceof StaggeredGridLayoutManager) {
    
    
            int[] positions = new int[((StaggeredGridLayoutManager) layoutManager).getSpanCount()];
            ((StaggeredGridLayoutManager) layoutManager).findLastVisibleItemPositions(positions);
            ((StaggeredGridLayoutManager) layoutManager).findFirstVisibleItemPositions(positions);
            ((StaggeredGridLayoutManager) layoutManager).findFirstCompletelyVisibleItemPositions(positions);
            ((StaggeredGridLayoutManager) layoutManager).findLastCompletelyVisibleItemPositions(positions);
            
            int maxPosition = positions[0];
            int minPosition = positions[0];
            for (int position : positions) {
    
    
                maxPosition = Math.max(maxPosition, position);
                minPosition = Math.min(minPosition, position);
            }
        }
    }
});

代码示例:

mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
    
    
    @Override
    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
    
    
        super.onScrolled(recyclerView, dx, dy);
        LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
        int firstCompletelyVisibleItemPosition = layoutManager.findFirstCompletelyVisibleItemPosition();
        if (firstCompletelyVisibleItemPosition == 0) {
    
    
            //滑动到顶部
        }
        int lastCompletelyVisibleItemPosition = layoutManager.findLastCompletelyVisibleItemPosition();
        if (lastCompletelyVisibleItemPosition == layoutManager.getItemCount() - 1) {
    
    
            //滑动到底部
        }
    }
});

在滑动到底部可以作分页加载的加载下一页。

记录位置、滑动到记录的位置

记录位置

mLayoutManager.findFirstVisibleItemPosition() 结合 firstVisibleView.getTop()

 int findFirstVisibleItemPosition = mLayoutManager.findFirstVisibleItemPosition();
 View firstVisibleView = mLayoutManager.findViewByPosition(findFirstVisibleItemPosition);
 int offset = firstVisibleView.getTop();

滑到上次记录位置

使用:LayoutManager#scrollToPositionWithOffset(int, int),可以比较精确地滑动到记录的具体位置。

 mLayoutManager.scrollToPositionWithOffset(firstVisibleItemPosition, offset);

也可以使用 LayoutManager#scrollToPosition(int),但是不够精确,只能滑动到某个item的位置。
也可以使用LayoutManager#computeXxx()系列,也不够准确,而且compute系列貌似主要用于支持滚动条(scrollbar)。在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/wangxiaocheng16/article/details/104265761