RecyclerView的滚动事件分析

简介:

列表的滚动一般分为两种:

  1. 手指按下 -> 手指拖拽列表移动 -> 手指停止拖拽 -> 抬起手指

  2. 手指按下 -> 手指快速拖拽后抬起手指 -> 列表继续滚动 -> 停止滚动

从上面可以看出,滚动状态分为:

|--静止
|--滚动
    |--被迫拖拽移动
    |--自己滚动

上面的过程的状态变化如下:

  1. 静止 -> 被迫拖拽移动 -> 静止

  2. 静止 -> 被迫拖拽移动 -> 自己滚动 -> 静止

<!--more-->

监听RecyclerView的滚动

好了,我们分析完滚动的过程,再看看如何监听RecyclerView的滚动.查看源码是最好的方法.

看源码

查看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); }

也就是说有两种方式可以监听滚动事件:

  1. 其中 setOnScrollListener 已经过时( 设置的监听器源码如下:

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

    以上代码中输出了主要个几个信息:

    1. newState : 目前的状态

    2. dx : 水平滚动距离

    3. dy : 垂直滚动距离

    onScrollStateChanged 方法

  2. recyclerView : 当前在滚动的RecyclerView

  3. 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;

onScrolled 方法

  • 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.顶端与底部

以上信息中还打印了

RecyclerView.canScrollVertically(-1)的值表示是否滚动到顶部

封装

基于以上,我们可以封装一个可以回调滚动状态和方向的RecyclerView.

先建立事件监听的接口public interface OnScrollCallback { voidonStateChanged(ScrollRecycler recycler, int state); voidonScrollUp(ScrollRecycler recycler, int dy); voidonScrollDown(ScrollRecycler recycler, int dy); }

再写一个类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); } } }); }

    本文转自 一点点征服   博客园博客,原文链接:http://www.cnblogs.com/ldq2016/p/6645952.html,如需转载请自行联系原作者

相关文章
|
6月前
|
Web App开发 小程序 Android开发
uniapp TC-scroll-view 横向和纵向滚动 带滚动回调
uniapp TC-scroll-view 横向和纵向滚动 带滚动回调
104 0
|
6月前
|
iOS开发 容器
在做动画的控件不触发手势事件问题及解决方案
在做动画的控件不触发手势事件问题及解决方案
36 0
|
iOS开发
iOS开发 - ScrollView滚动时怎么判断滚动停止及滚动的方向
iOS开发 - ScrollView滚动时怎么判断滚动停止及滚动的方向
891 0
|
存储 缓存 索引
更好的 RecyclerView 表项子控件点击监听器
上篇介绍了一种新的监听 RecyclerView 表项点击事件的方法。实现了将点击事件和RecyclerView.Adapter解耦。这一篇介绍如何监听 RecyclerView 表项子控件点击事件。
586 0
|
缓存 算法
图文DEMO并茂讲解RecyclerView滑动时回收和复用触发的时机
图文DEMO并茂讲解RecyclerView滑动时回收和复用触发的时机
图文DEMO并茂讲解RecyclerView滑动时回收和复用触发的时机
|
Dart 开发者
【Flutter】监听滚动动作 控制组件 透明度渐变 ( 移除顶部状态栏空白 | 帧布局组件 | 透明度组件 | 监听滚动组件 )(三)
【Flutter】监听滚动动作 控制组件 透明度渐变 ( 移除顶部状态栏空白 | 帧布局组件 | 透明度组件 | 监听滚动组件 )(三)
230 0
【Flutter】监听滚动动作 控制组件 透明度渐变 ( 移除顶部状态栏空白 | 帧布局组件 | 透明度组件 | 监听滚动组件 )(三)
【Flutter】监听滚动动作 控制组件 透明度渐变 ( 移除顶部状态栏空白 | 帧布局组件 | 透明度组件 | 监听滚动组件 )(二)
【Flutter】监听滚动动作 控制组件 透明度渐变 ( 移除顶部状态栏空白 | 帧布局组件 | 透明度组件 | 监听滚动组件 )(二)
249 0
20.LinearSmoothScroller源码分析(26.0.0)-控制RecyclerView滑动速度
smoothScrollToPosition方法可以使RecyclerView滑动到指定的位置,来看下源码 /** * Starts a smooth scroll to an adapter position.
2416 0
|
Android开发
Android StaggeredGridLayoutManager布局RecyclerView在滚动状态可见范围刷新数据
Android StaggeredGridLayoutManager布局RecyclerView在滚动状态可见范围刷新数据 之所以把StaggeredGridLayoutManager布局的RecyclerView单列出...
3336 0