事件分发影响到自定义控件以及处理一些特殊问题时候特别有用,一直没有总结一下,导致
在碰到问题的时候思路不够清晰,其实对于单个View的事件分发其实很简单,稍微复杂点的其实
是在有ViewGroup的情况下。也不用举什么例子,直接就总结吧:
针对单个View
所有的事件都从ACTION_DOWN开始,入口是dispatchTouchEvent,因为对于单个View没有拦截之说,所以在dispatchTouchEvent里面只是判断View有没有设置touch监听或者点击,如果有,那么事件就接管了,后续的事件都会直接发给这个View
针对ViewGroup:
一共有三个方法 dispatchTouchEvent onInterceptTouchEvent onTouchEvent,主要是说清楚这三个方法之间的关系
dispatchTouch一样是入口,同样是从ACTION_DOWN开始,先是在dispatchTouchEvent里面调用了onInterceptTouchEvent,问ViewGroup自己需要拦截吗,如果拦截了,那么后续事件就交给ViewGroup的onTouchEvent,当然后续事件调用的方法顺序就是:dispatchTouchEvent(ViewGroup)————>onTouchEvent(ViewGroup);但是如果ACTION_DOWN事件被子View接管了,那么后续事件的调用的顺序:
dispatchTouchEvent(ViewGroup)————>onInterceptTouchEvent(ViewGroup)————>onTouchEvent(View)
但是如果View接管了事件,但是后续事件被ViewGroup拦截了的话,那么View还是会收到一个Cancel事件。
其中ACTION_DOWN没有被ViewGroup拦截的情况下子View接受了ACTION_DOWN事件,然而后续事件还会先通过ViewGroup的onInterceptTouchEvent然后发给子View,其实这个机制的设计是非常有意思的,因为有些情况(或者说很多情况)下我们在手指下去的时候还无法判断究竟谁来接管事件,但是到了发生Move这一步,我们基本上就可以知道怎么处理了。比如每天都用到的RecyclerView,我们既可以滑动Item也可以点击,就是靠这个机制才得以实现的,当手指下去然后松手这中间没有Move直接UP,那么就是一个点击事件,发生Move则会判定为滑动。
以上的总结本身在ViewGroup的onInterceptTouchEvent方法中有注释,之前没耐心看,最近因为和事件分发走的近,必须好好看懂这一块
总之View只有一次机会来接管事件,也就是在ACTION_DOWN传过来的时候,不然以后都没机会了,直到下一次ACTION_DOWN来临。假如谁都不管这个事件,那么最后就会一直冒泡到Activity的onTouchEvent中去(这个很好验证,写个空白布局,重写下Activity的onTouchEvent,里面打个日志就知道了 )因为如此,Android也推出了嵌套滚动,其实就是让子View无脑接管事件,但是呢,会在处理事件前先给parent处理,然后剩下的给自己,这样就让有些不好实现的效果(比如联动)好做很多