本文主要分析RecyclerView的onInterceptTouchEvent()对三种事件怎么处理的
这里只放了一些比较重要点的代码,有一部分省略
先看onInterceptTouchEvent()的返回值
return mScrollState == SCROLL_STATE_DRAGGING
解释一下mScrollState这个变量,代表RecyclerView的滑动状态,它一共有三种值
public static final int SCROLL_STATE_IDLE = 0; // 滑动停止public static final int SCROLL_STATE_DRAGGING = 1; //正在被用户滑动public static final int SCROLL_STATE_SETTLING = 2;//正在自动滑动,这个大家日常应该都遇到过,当我们快速滑动然后抬起手时会发生自动滑动
ACTION_DOWN
@Overridepublic boolean onInterceptTouchEvent(MotionEvent e) {...switch (action) {case MotionEvent.ACTION_DOWN:...if (mScrollState == SCROLL_STATE_SETTLING) {getParent().requestDisallowInterceptTouchEvent(true);setScrollState(SCROLL_STATE_DRAGGING);stopNestedScroll(TYPE_NON_TOUCH);}...break;...}return mScrollState == SCROLL_STATE_DRAGGING;}
down事件主要看中间的判断部分,如果当前的滑动状态是自动滑动(SCROLL_STATE_SETTLING)状态,则将滑动状态置为正在滑动(SCROLL_STATE_DRAGGING),然后停止滑动,这样就对down事件做了拦截,其实很好理解:当你的列表在自动快速滚动的过程中,手指再按上去,是需要停止滑动的;
所以只有这种情况RecyclerView才会拦截down事件,其他情况分发给子view
ACTION_MOVE
case MotionEvent.ACTION_MOVE: {...final int x = (int) (e.getX(index) + 0.5f);final int y = (int) (e.getY(index) + 0.5f);if (mScrollState != SCROLL_STATE_DRAGGING) {final int dx = x - mInitialTouchX;final int dy = y - mInitialTouchY;boolean startScroll = false;if (canScrollHorizontally && Math.abs(dx) > mTouchSlop) {mLastTouchX = x;startScroll = true;}if (canScrollVertically && Math.abs(dy) > mTouchSlop) {mLastTouchY = y;startScroll = true;}if (startScroll) {setScrollState(SCROLL_STATE_DRAGGING);}}} break;
move事件处理就很好理解了,如果当前滚动状态是正在滑动,就直接拦截;如果不是,则判断x轴和y轴上滑动距离是否超过最小滑动距离,超过了就将滚动状态置为正在滑动状态,然后拦截;
ACTION_UP
case MotionEvent.ACTION_UP: {mVelocityTracker.clear();stopNestedScroll(TYPE_TOUCH);} break;
up事件除了停止滑动什么也没干,如果当前是正在滑动状态直接拦截,否则分发子view
总结
RecyclerView对三种事件的处理:
down事件:如果当前处于自动滚动状态,则拦截事件,停止滚动,否则分发给子view
move事件:如果当前处于正在滑动状态直接拦截,否则判断水平位置与竖直为滑动距离是否超过最小滑动距离(mTouchSlop),超过则拦截,否则不拦截
up事件:只做了停止滑动操作,是否拦截依赖当前滑动状态