ScrollView滚动事件和滚动状态(开始、停止)的监听实现

监听ScrollView滚动事件

方式一

  1. mScrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
  2. @Override
  3. public void onScrollChanged() {
  4. Log.d("MainActivity", "getViewTreeObserver - onScrollChanged");
  5. }
  6. });

方式二

SdkVersion >= 23时,可直接设置OnScrollChangeListener

  1. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
  2. mScrollView.setOnScrollChangeListener(new View.OnScrollChangeListener() {
  3. @Override
  4. public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
  5. Log.d("MainActivity", "setOnScrollChangeListener - onScrollChange");
  6. }
  7. });
  8. }

低版本SDK,可以覆写ScrollView中的onScrollChange方法实现监听。

监听ScrollView滚动状态变化(滚动开始、滚动停止)

ListView有个setOnScrollListener的接口,可以监听滚动状态变化,有三种状态:

  • 用户触摸状态下的滚动(TOUCH_SCROLL)
  • 用户释放手指后继续滚动(FLING)
  • 滚动停止(IDLE)

但ScrollView没有提供这种接口。

自己实现监听滚动停止比较简单的一个思路是:触发滚动后,不断读取ScrollView的ScrollY,当两次ScrollY相同时,认为滚动停止了。

判断手指是否按下的实现

区分TOUCH_SCROLL和FLING状态的方法是,通过判断Touch事件,记录当前用户手指是否处于按下状态。

处理ACTION_DOWN事件,应该在ScrollView的onInterceptTouchEvent中实现;
而处理ACTION_UP和ACTION_CANCEL事件,应该在ScrollView的onTouchEvent中实现。

判断滚动是否停止

每次回调onScrollChange时,清除并重启一个延时计时器,计时完成后读取ScrollY,同时启动下一次计时,判断两次ScrollY相同,则置为IDLE状态。

当用户手指处于按下状态时,即使两次检测到ScrollY相同,也不能视为滚动停止。

计时器的间隔要取合适。取太长,会导致检测到滚动停止的延迟比较长;如果取太短,会造成滚动快要停止时,由于滚动很慢,两次间隔时间点可能都没有滚动,造成误判。

完整代码可在GitHub查看:
https://github.com/jzj1993/ObservableScrollView/blob/master/library/src/main/java/com/jzj/view/ObservableScrollView.java

ObservableScrollView

ObservableScrollView是一个可以实现滚动状态监听的开源项目。已经发布到JCenter,可直接通过gradle引用,配置如下。

最新版本请移步项目主页:https://github.com/jzj1993/ObservableScrollView

  1. dependencies {
  2. //...
  3. compile 'com.jzj.view:ObservableScrollView:0.0.2'
  4. }