Recyclerview滑动事件简单分析

        前言:这篇文章主要是针对上一篇做个补充。在写上一篇文章的时候,疑惑为什么每次滑动的时候RecyclerView.OnScrollListener的onScrollStateChanged只会在开始和结束的时候各调用一次,但是onScrolled方法会被回调很多次。看了下Recyclerview的源码,终于了解了大概原理,所以有了这篇文章。

正文

        手指从“按下-->滑动--> ... ->滑动 -->抬起”,一共有三类事件触发,分别是:

MotionEvent.ACTION_DOWN-->MotionEvent.ACTION_MOVE-->...->MotionEvent.ACTION_MOVE->MotionEvent.ACTION_UP

滑动监听器:

public abstract static class OnScrollListener {
        
   public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState){}
      
   public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy){}
}

当在Recyclerview页面上滑动时,会走到Recyclerview的onTouchEvent回调方法,其内部对各种触摸事件进行处理。下面分别说明:

1、MotionEvent.ACTION_DOWN

        手指按下,回调onTouchEvent,并判断事件为MotionEvent.ACTION_DOWN,这里没有关于滑动监听器的逻辑,可以略过,其代码为:

@Override
public boolean onTouchEvent(MotionEvent e) {

    switch (action) {
        case MotionEvent.ACTION_DOWN: {
            ...
    }        
}

2、MotionEvent.ACTION_MOVE

        开始滑动,回调onTouchEvent,并判断事件为MotionEvent.ACTION_MOVE,其内部逻辑为:

@Override
public boolean onTouchEvent(MotionEvent e) {

    switch (action) {
        case MotionEvent.ACTION_DOWN: {
            ...
            break
        }
        case MotionEvent.ACTION_MOVE: {
            ...
            if (mScrollState != SCROLL_STATE_DRAGGING) {
               ...
               setScrollState(SCROLL_STATE_DRAGGING);
               ...
            }
            if (mScrollState == SCROLL_STATE_DRAGGING) {
                if (scrollByInternal(
                    canScrollHorizontally ? dx : 0,
                    canScrollVertically ? dy : 0, e)) {
                    getParent().requestDisallowInterceptTouchEvent(true);
                 }
            }
            ...
            break
        }
    }        
}

其中mScrollState初始值为SCROLL_STATE_IDLE

private int mScrollState = SCROLL_STATE_IDLE;

所以第一次进入到MotionEvent.ACTION_MOVE内部逻辑时,条件mScrollState != SCROLL_STATE_DRAGGING为true,所以设置mScrollState状态为SCROLL_STATE_DRAGGING。在setScrollState(SCROLL_STATE_DRAGGING)方法内部最后会调用到滑动监听器RecyclerView.OnScrollListener的onScrollStateChanged()方法。

setScrollState(SCROLL_STATE_DRAGGING) -> dispatchOnScrollStateChanged(state) ->mScrollListeners.get(i).onScrollStateChanged(this, state);

从第二个MotionEvent.ACTION_MOVE事件发生后,mScrollState = SCROLL_STATE_DRAGGING,所以会走if (mScrollState == SCROLL_STATE_DRAGGING) {}内部的逻辑。在这个内部最后有执行到RecyclerView.OnScrollListener的onScrolled()方法。

scrollByInternal() -> dispatchOnScrolled() -> mScrollListeners.get(i).onScrolled(this, hresult, vresult)

因为一次滑动,会触发很多个MotionEvent.ACTION_MOVE事件,所以OnScrollListener的onScrolled()方法会被调用很多次。

3、MotionEvent.ACTION_UP

        抬起手指,触发MotionEvent.ACTION_UP事件,把mScrollState状态还原成最初状态SCROLL_STATE_IDLE。这样当再次按下手指滑动时,又从头开始啦。

@Override
public boolean onTouchEvent(MotionEvent e) {

    switch (action) {
        case MotionEvent.ACTION_DOWN: {
            ...
            break
        }
        case MotionEvent.ACTION_MOVE: {
            ...
            if (mScrollState != SCROLL_STATE_DRAGGING) {
               ...
               setScrollState(SCROLL_STATE_DRAGGING);
               ...
            }
            if (mScrollState == SCROLL_STATE_DRAGGING) {
                if (scrollByInternal(
                    canScrollHorizontally ? dx : 0,
                    canScrollVertically ? dy : 0, e)) {
                    getParent().requestDisallowInterceptTouchEvent(true);
                 }
            }
            ...
            break
        }
        case MotionEvent.ACTION_MOVE: {
            ...
            setScrollState(SCROLL_STATE_IDLE);
            ...
        }
    }        
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值