开始以前,咱们想一下一个列表的滚动过程是怎样的?java
列表的滚动通常分为两种:git
手指按下 -> 手指拖拽列表移动 -> 手指中止拖拽 -> 抬起手指github
手指按下 -> 手指快速拖拽后抬起手指 -> 列表继续滚动 -> 中止滚动微信
从上面能够看出,滚动状态分为:ide
|--静止 |--滚动 |--被迫拖拽移动 |--本身滚动
上面的过程的状态变化以下:测试
静止 -> 被迫拖拽移动 -> 静止this
静止 -> 被迫拖拽移动 -> 本身滚动 -> 静止spa
<!--more-->.net
好了,咱们分析完滚动的过程,再看看如何监听RecyclerView的滚动.查看源码是最好的方法.code
查看RecyclerView的源码,咱们能够看到如下代码:
/** * Set a listener that will be notified of any changes in scroll state or position. * @param listener Listener to set or null to clear * @deprecated Use {@link #addOnScrollListener(OnScrollListener)} and * {@link #removeOnScrollListener(OnScrollListener)} */ @Deprecated public void setOnScrollListener(OnScrollListener listener) { mScrollListener = listener; } /** * Add a listener that will be notified of any changes in scroll state or position. * <p>Components that add a listener should take care to remove it when finished. * Other components that take ownership of a view may call {@link #clearOnScrollListeners()} * to remove all attached listeners.</p> * @param listener listener to set or null to clear */ public void addOnScrollListener(OnScrollListener listener) { if (mScrollListeners == null) { mScrollListeners = new ArrayList<>(); } mScrollListeners.add(listener); }
也就是说有两种方式能够监听滚动事件:
setOnScrollListener()
addOnScrollListener()
其中 setOnScrollListener 已通过时(@deprecated
),建议使用 addOnScrollListener.若是在源码中没有 addOnScrollListener 方法,可能你的版本过旧,请升级recyclerview包.
设置的监听器源码以下:
public abstract static class OnScrollListener { /** * Callback method to be invoked when RecyclerView's scroll state changes. * @param recyclerView The RecyclerView whose scroll state has changed. * @param newState The updated scroll state. One of {@link #SCROLL_STATE_IDLE}, * {@link #SCROLL_STATE_DRAGGING} or {@link #SCROLL_STATE_SETTLING}. */ public void onScrollStateChanged(RecyclerView recyclerView, int newState){} /** * Callback method to be invoked when the RecyclerView has been scrolled. This will be * called after the scroll has completed. * <p> * This callback will also be called if visible item range changes after a layout * calculation. In that case, dx and dy will be 0. * * @param recyclerView The RecyclerView which scrolled. * @param dx The amount of horizontal scroll. * @param dy The amount of vertical scroll. */ public void onScrolled(RecyclerView recyclerView, int dx, int dy){} }
在滚动过程当中,此监听器会回调两个方法.
onScrollStateChanged : 滚动状态变化时回调
onScrolled : 滚动时回调
这二者的区别在于: 状态与过程
注 : 如下源码可在最后的地址中找到.
demoRv = (RecyclerView) findViewById(R.id.demo_rv); layoutManager = new LinearLayoutManager(this); demoRv.setLayoutManager(layoutManager); demoRv.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST)); bookAdapter = new BookAdapter(); bookAdapter.fillList(MockService.getBookList()); demoRv.setAdapter(bookAdapter); demoRv.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); Log.i(TAG, "-----------onScrollStateChanged-----------"); Log.i(TAG, "newState: " + newState); } @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); Log.i(TAG, "-----------onScrolled-----------"); Log.i(TAG, "dx: " + dx); Log.i(TAG, "dy: " + dy); Log.i(TAG, "CHECK_SCROLL_UP: " + recyclerView.canScrollVertically(TAG_CHECK_SCROLL_UP)); Log.i(TAG, "CHECK_SCROLL_DOWN: " + recyclerView.canScrollVertically(TAG_CHECK_SCROLL_DOWN)); } });
以上代码中输出了主要个几个信息:
newState : 目前的状态
dx : 水平滚动距离
dy : 垂直滚动距离
在void onScrollStateChanged(RecyclerView recyclerView, int newState)
中回调两个变量:
recyclerView : 当前在滚动的RecyclerView
newState : 当前滚动状态.
其中newState有三种值:
//正在滚动 public static final int SCROLL_STATE_IDLE = 0; //正在被外部拖拽,通常为用户正在用手指滚动 public static final int SCROLL_STATE_DRAGGING = 1; //自动滚动开始 public static final int SCROLL_STATE_SETTLING = 2;
在void onScrolled(RecyclerView recyclerView, int dx, int dy)
方法中回调了三个变量:
recyclerView : 当前滚动的view
dx : 水平滚动距离
dy : 垂直滚动距离
运行以上代码,而后按照上面的滚动过程分别进行两种滚动.
第一种方式缓慢滚动结果以下:
I/MainActivity: -----------onScrollStateChanged----------- I/MainActivity: newState: 1 I/MainActivity: -----------onScrolled----------- I/MainActivity: dx: 0 I/MainActivity: dy: -6 I/MainActivity: CHECK_SCROLL_UP: true I/MainActivity: CHECK_SCROLL_DOWN: true ------------------------n个onScrolled-------------------- I/MainActivity: -----------onScrolled----------- I/MainActivity: dx: 0 I/MainActivity: dy: -2 I/MainActivity: CHECK_SCROLL_UP: true I/MainActivity: CHECK_SCROLL_DOWN: false I/MainActivity: -----------onScrollStateChanged----------- I/MainActivity: newState: 0
第二种快速滚动结果以下:
I/MainActivity: -----------onScrollStateChanged----------- I/MainActivity: newState: 1 I/MainActivity: -----------onScrolled----------- I/MainActivity: dx: 0 I/MainActivity: dy: 59 I/MainActivity: CHECK_SCROLL_UP: true I/MainActivity: CHECK_SCROLL_DOWN: true --------------------------n个onScrolled------------------- I/MainActivity: -----------onScrolled----------- I/MainActivity: dx: 0 I/MainActivity: dy: 54 I/MainActivity: CHECK_SCROLL_UP: true I/MainActivity: CHECK_SCROLL_DOWN: true I/MainActivity: -----------onScrollStateChanged----------- I/MainActivity: newState: 2 I/MainActivity: -----------onScrolled----------- I/MainActivity: dx: 0 I/MainActivity: dy: 56 I/MainActivity: CHECK_SCROLL_UP: true I/MainActivity: CHECK_SCROLL_DOWN: true --------------------------n个onScrolled------------------- I/MainActivity: -----------onScrolled----------- I/MainActivity: dx: 0 I/MainActivity: dy: 14 I/MainActivity: CHECK_SCROLL_UP: true I/MainActivity: CHECK_SCROLL_DOWN: true I/MainActivity: -----------onScrolled----------- I/MainActivity: dx: 0 I/MainActivity: dy: 1 I/MainActivity: CHECK_SCROLL_UP: true I/MainActivity: CHECK_SCROLL_DOWN: true I/MainActivity: -----------onScrollStateChanged----------- I/MainActivity: newState: 0
且在滚动过程当中发现:
1.滚动方向
dy > 0 时为向上滚动
dy < 0 时为向下滚动
2.回调过程
缓慢拖拽回调过程:
1. newState = RecyclerView.SCROLL_STATE_DRAGGING; 2. dy 屡次改变 3. newState = RecyclerView.SCROLL_STATE_IDLE
快速滚动回调过程:
1. newState = RecyclerView.SCROLL_STATE_DRAGGING; 2. dy 屡次改变 3. newState = RecyclerView.SCROLL_STATE_SETTLING; 4. dy 屡次改变 5. newState = RecyclerView.SCROLL_STATE_IDLE;
3.顶端与底部
以上信息中还打印了canScrollVertically
的信息,其中:
RecyclerView.canScrollVertically(1)
的值表示是否滚动到底部RecyclerView.canScrollVertically(-1)
的值表示是否滚动到顶部
基于以上,咱们能够封装一个能够回调滚动状态和方向的RecyclerView.
先创建事件监听的接口OnScrollCallback
,代码以下:
public interface OnScrollCallback { void onStateChanged(ScrollRecycler recycler, int state); void onScrollUp(ScrollRecycler recycler, int dy); void onScrollDown(ScrollRecycler recycler, int dy); }
再写一个类ScrollRecycler
继承RecyclerView
,在类中添加如下方法:
public void setOnScrollCallback(final OnScrollCallback callback) { if (callback == null) { return; } addOnScrollListener(new OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); callback.onStateChanged(ScrollRecycler.this, newState); } @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); if (dy > 0) { callback.onScrollDown(ScrollRecycler.this, dy); } else { callback.onScrollUp(ScrollRecycler.this, dy); } } }); }
测试如下是否可行,下面直接给出测试结果:
I/MainActivity: onStateChanged: state:1 I/MainActivity: onScrollDown: 7 I/MainActivity: onScrollDown: 4 I/MainActivity: onScrollDown: 4 I/MainActivity: onScrollDown: 4 I/MainActivity: onStateChanged: state:0 I/MainActivity: onStateChanged: state:1 I/MainActivity: onScrollUp: -11 I/MainActivity: onScrollUp: -8 I/MainActivity: onScrollUp: -9 I/MainActivity: onStateChanged: state:0
完毕,以上就是对RecyclerView的滚动的简单研究,项目代码地址以下:Dev-Wiki/RecyclerScroll: RecyclerView滚动的Demo
更多文章请移步个人博客:DevWiki Blog
重要说明
想随时获取最新博客文章更新,请关注公共帐号DevWiki,或扫描下面的二维码: