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)。在这里插入图片描述

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值