RecyclerView滚动事件分析与OnScrollListener的使用
作为一个目前在Android开发中可能是应用最为广泛之一的组件,RecyclerView在诞生之初就广受好评。而随着对其研究的深入,我们会对它有很多使用需求,一个能滚动的组件,需要监控其滚动事件是非常正常的事情。
一、列表的滚动事件:
一个列表在滚动的时候,一般会有两种滚动形式:
- 手指按下后,不离开屏幕,一直拖动着列表进行滚动,滚动到合适的位置后停下来,手指离开屏幕。
- 手指按下,在很短时间内用较快的速度拖动列表,然后手指马上离开列表,列表随着惯性,继续滚动到一个位置(或者滚动到尾部)。
二、如何监听RecyclerView的滚动事件
稍有经验的开发者,都不难猜到会有一个Listener,在Android Studio里面直接用一个RecyclerView对象进行set或者add的时候,IDE就会提示相应的Listener。是的,Google给我们提供了一个RecyclerView下的OnScrollListener,你可以用addOnScrollListener或setOnScrollListener(已经deprecated了,不建议使用)的方式来监听,下面我们来看看它的源码:
/**
* An OnScrollListener can be added to a RecyclerView to receive messages when a scrolling event
* has occurred on that RecyclerView.
* <p>
* @see RecyclerView#addOnScrollListener(OnScrollListener)
* @see RecyclerView#clearOnChildAttachStateChangeListeners()
*
*/
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){}
}
OnScrollListener提供了2个回掉方法,但由于OnScrollListener不是接口而是抽象类,所以你并不是必须同时实现这2个方法,可以根据实际需求来进行实现。下面来看一下这2个方法都有什么作用。
onScrollStateChanged(RecyclerView recyclerView, int newState)
很容易看出来,这个方法记录了RecyclerView的滚动状态的变化,2个变量中,第一个自然是当前的RecyclerView组件,第二个则表达了当前滚动状态,它有3个值:
/**
* The RecyclerView is not currently scrolling.
* @see #getScrollState()
*/
public static final int SCROLL_STATE_IDLE = 0;
/**
* The RecyclerView is currently being dragged by outside input such as user touch input.
* @see #getScrollState()
*/
public static final int SCROLL_STATE_DRAGGING = 1;
/**
* The RecyclerView is currently animating to a final position while not under
* outside control.
* @see #getScrollState()
*/
public static final int SCROLL_STATE_SETTLING = 2
我特别欣慰,这次Google自己写的注释很详细了。当然如果你英语水平不高我可以给你翻译一下:
-
SCROLL_STATE_IDLE代表RecyclerView现在不是滚动状态。
-
SCROLL_STATE_DRAGGING代表RecyclerView处于被外力引导的滚动状态,比如手指正在拖着进行滚动。
-
SCROLL_STATE_SETTLING代表RecyclerView处于自动滚动的状态,此时手指已经离开屏幕,RecyclerView的滚动是自身的惯性在维持。
onScrolled(RecyclerView recyclerView, int dx, int dy)
此方法用来获取RecyclerView的滚动距离,dx和dy自然分别代表横向和纵向的滚动距离啦,这2个值都是可正可负的: -
当dx > 0 时,代表手指向左拖动,RecyclerView则从右向左滚动。
-
当dx < 0时,代表手指向右拖动,RecyclerView则从左向右滚动。
-
当dy > 0时,代表手指向上拖动,RecyclerView则从上向下滚动(就是我们最常见的,从顶部开始往下滚动)。
-
当dy < 0时,代表手指向下拖动,RecyclerView则从下向上滚动(就是从列表底部往回挥动)。
这里再介绍2个很有用的方法: -
public boolean canScrollVertically(int direction)
-
public boolean canScrollHorizontally(int direction)
这2个方法实际上并不是RecyclerView所特有的,而是View这个超级类的。这2个方法,可以判断当前View能否在横向或纵向上滚动。当返回false的时候,说明组件已经不能在给定的方向上进行滚动了,而这2个方法,也可以引出一个很常见的问题及解决办法。
三、如何判断RecyclerView是否滚动到底部或顶部?
以更常见的纵向来说,使用Recyclerview. canScrollVertically(1),当返回值是false的时候,代表你的RecyclerView不能继续往下滚动啦,也就是说已经滚动到底部了。同理,当Recyclerview. canScrollVertically(-1)返回false的时候代表RecyclerView不能继续网上滚动了,已经到顶部了。这个方法比通过计算当前item的位置以及总item数量的方法进行判断要好多了。