动机
今天st0rm23探究了一下recyclerView的事件拦截机制,我比较好奇,为啥我的拇指按在recyclerView的item上,如果滑动的话是recyclerView来进行响应,而点击的时候是item进行响应。按照之前我看的事件分发的原理来看,应该在DOWN的时候就决定了targetView是item,后面的事件move是怎么给recyclerView的呢?
拦截机制
看了源代码发现,其实是有Intercept和cancel机制的。
MOTION_DOWN:
父控件recyclerView的dispatchTouchEvent开始,InterceptTouchEvent返回的是false,也就是不拦截。那么流程正常进行,一直dispatch到了itemView,接着itemView响应了MOVE_DOWN的事件,传递链的targetView被设置成了itemView。
MOTION_MOVE:
同样是从父控件的recyclerView的dispatchTouchEvent,但是发现这是个MOVE事件检测后InterceptTouchEvent返回的是true。那么好了,要开始拦截了。
首先是调用dispatchTransformedTouchEvent(ev, cancelChild, target.child, target.pointerIdBits),传给原本的target一个MOTION_CANCEL事件让target将这个CANCEL事件传递下去,这个事件会使得child一下的view的触摸事件全部被取消掉。接着dispatchTouchEvent返回true,层层传递给父亲。
注意这次的MOTION_MOVE事件并没有使得recyclerView滚动,但是recyclerView的mTargetView被置为了null,也就是传递链的targetView被置为了recyclerView。
MOTION_MOVE:
这一次recyclerView真正成为了传递链的targetView,这时候传递到recyclerView的时候,recyclerView就会传递给自己的onTouchEvent,这样就可以正常地执行这个滚动操作了。
总结:
也就是在滑动的时候,recyclerView阻截了事件,传递给儿子的是CANCEL事件,同时让自己变成了传递链的末尾,并且消耗了一个motion_move事件。第二个motion_move的时候才会真正开始执行该move的滑动。