RecyclerView的滚动事件分析
列表的滚动一般分为两种:
手指按下 -> 手指拖拽列表移动 -> 手指停止拖拽 -> 抬起手指
手指按下 -> 手指快速拖拽后抬起手指 -> 列表继续滚动 -> 停止滚动
从上面可以看出,滚动状态分为:
|--静止
|--滚动
|--被迫拖拽移动
|--自己滚动
上面的过程的状态变化如下:
静止 -> 被迫拖拽移动 -> 静止
静止 -> 被迫拖拽移动 -> 自己滚动 -> 静止
<!--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);
}
也就是说有两种方式可以监听滚动事件:
其中 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));
}
});以上代码中输出了主要个几个信息:
newState : 目前的状态
dx : 水平滚动距离
dy : 垂直滚动距离
onScrollStateChanged 方法
在
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;
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 { void onStateChanged(ScrollRecycler recycler, int state); void onScrollUp(ScrollRecycler recycler, int dy); void onScrollDown(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);
}
}
});
}
RecyclerView的滚动事件分析的更多相关文章
- RecyclerView的滚动事件OnScrollListener研究
(1)滚动事件分类 列表的滚动一般分为两种: 1.手指按下 -> 手指拖拽列表移动 -> 手指停止拖拽 -> 抬起手指 2.手指按下 -> 手指快速拖拽后抬起手指 -> ...
- js网页滚动条滚动事件实例分析
本文实例讲述了js网页滚动条滚动事件用法.分享给大家供大家参考.具体分析如下: 在做js返回顶部的效果时,要监听网页滚动条滚动事件,这个事件就是:window.onscroll.当onscroll事件 ...
- 死磕到底RecyclerView | RecyclerView 的滚动是怎么实现的?
RecyclerView 是一个展示列表的控件,其中的子控件可以被滚动.这是怎么实现的?以走查源码的方式一探究竟. 切入点:滚动事件 阅读源码时,如何在浩瀚的源码中选择合适的切入点很重要,选好了能少走 ...
- 在RecyclerView列表滚动的时候显示或者隐藏Toolbar
先看一下效果: 本文将讲解如何实现类似于Google+应用中,当列表滚动的时候,ToolBar(以及悬浮操作按钮)的显示与隐藏(向下滚动隐藏,向上滚动显示),这种效果在Material Design ...
- js鼠标滑轮滚动事件绑定(兼容主流浏览器)
/** Event handler for mouse wheel event. *鼠标滚动事件 */ var wheel = function(event) { var delta = 0; if ...
- 鼠标滚动事件兼容性 wheel、onwheel
wheelEvent = "onwheel" in document.createElement("div") ? "wheel" : // ...
- JavaScript----分层导航 滚动事件
分层导航 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3 ...
- JS鼠标滚动事件
-----------------------------//鼠标滚动事件以下是JS临听鼠标滚动事件 并且还考虑到了各浏览器的兼容----------------------------------- ...
- Jquery-Mobile滚动事件
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> < ...
随机推荐
- RSA进阶之维纳攻击(wiener-attack )
维纳攻击: 场景:e很大 例题: 第七届山东网络安全技能大赛 链接:https://pan.baidu.com/s/1IRInw3pB7SQfp3MxRJW17A 提取码:lcn3 e很大,妥了,维纳 ...
- 详细的Windows下安装 binwalk
1. https://github.com/ReFirmLabs/binwalk到这里下载binwalk,下载后解压. 2. 找到下载后的文件夹, 在这里要进行安装步骤,一边按着shift,一边按着鼠 ...
- python-day4-内置函数2
摘要:python中有好多可用性特别强的内置函数,熟练掌握对于以后的编程过程中有很大的帮助~~~~ callable函数.chr函数与ord函数.random函数.compile函数.evec与eva ...
- dib build ipa image Injection password
针对dib制作的deploy image,注入密码有两种方式: devuser/dynamic-login .对应 dib 添加密码,是通过 dynamic-login element 来完成的. 首 ...
- java面试需要准备什么呢?c++可以看看
作者:Mingche Su链接:https://zhuanlan.zhihu.com/p/20545626来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 语言知识点:以 ...
- 最简单的动态代理实例(spring基于接口代理的AOP原理)
JDK的动态代理是基于接口的 package com.open.aop; public interface BusinessInterface { public void processBus ...
- java BigDecimal工具类
package com.core.calculate; import java.math.BigDecimal; import java.text.DecimalFormat; /** * Creat ...
- 【bzoj4896】[Thu Summer Camp2016]补退选 Trie树+STL-vector
题目描述 X是T大的一名老师,每年他都要教授许多学生基础的C++知识.在T大,每个学生在每学期的开学前都需要选课,每次选课一共分为三个阶段:预选,正选,补退选:其中"补退选"阶段最 ...
- 多线程(实现Runnable接口)
/** * 创建一个子线程, 完成1-100之间自然数的输出,同样的主线程执行同样的操作 *创建多线程的第二种方式,通过实现的方式 * 继承和实现的方式对比 * 一,联系: * public cla ...
- linux系统程序设计教程
linux系统程序设计教程 第一章:生成一个Process(进程) 进程是什么?简单地说,进程就是在执行状态下的一个程序(包括CPU状态,所占内存的状态,等等) A进程生成了B进程,也就是说,A程序在 ...