我们前面分析了点击事件分发机制的源码。知道了,3个重要方法的关系。下面用伪代码来进行简单的表示:
public boolean dispatchTouchEvent(MotionEvent ev) {
boolean result = false;
if(onInterceptTouchEvent(ev)) {
result = onTouchEvent(ev);
} else {
result = child.dispatchTouchEvent(ev);
}
return result;
}
onInterceptTouchEvent和onTouchEvent方法都在dispatchTouchEvent方法中调用。现在我们根据这段伪代码来分析一下点击事件分发的传递规则。
首先来讲一下点击事件由上而下的传递规则,当点击事件产生后会由Activity来处理,传递给PhoneWindow,再传递给DecorView,最后传递给顶层的ViewGroup。一般在事件传递中,只考虑ViewGroup的onInterceptTouchEvent方法,因为一般情况下,我们不会重写dispatchTouchEvent方法。对于根ViewGroup,点击事件首先传递给它的dispatchTouchEvent方法。如果该ViewGroup的onInterceptTouchEvent方法返回true,则表示要拦截这个事件,这个事件就会交给它的onTouchEvent方法处理。如果该onIntercepterTouchEvent方法返回false,则表示不拦截这个事件,这个事件就会交给它的子元素的dispatchTouchEvent来处理。如此反复下去。如果传递给最底层的view,该view是没有子view的,这时就会调用View的dispatchTouchEvent方法。一般情况下,最终会调用View的onTouchEvent方法。
刘望舒用了武侠的例子,我们可以参考一下:
假设有人来武当闹事,这个消息首先汇报给了掌门人张三丰,张三丰自然不会亲自出马,于是他把任务交给武当七侠之一的宋远桥,也就是说张三丰的onInterceptTouchEvent()返回false,宋远桥觉得自己再怎么样也是武当七侠,也不需要自己出马,于是他把任务交给武当弟子宋青书。也就是宋远桥的onInterceptTouchEvent返回false,宋青书没有手下了,他只能自己迎战。这里,我们把张真人比作顶层ViewGroup,把武当七侠之一的宋远桥比较中层ViewGroup。武当弟子宋青书比较底层View.所以,我们得出结论,事件由上而下传递返回值的规则:
如果onInterceptTouchEvent方法返回true,则拦截,不继续向下传递;如果onInterceptTouchEvent方法返回false,则不拦截,继续向下传递。
下面再说说点击事件自下而上的传递过程。当点击事件传递给底层的View时,如果其onTouchEvent返回true,则事件由底层的View消耗并处理。如果onTouchEvent返回false,则表示该view不做处理。并传递给父View的onTouchEvent方法处理。如果父View的onTouchEvent方法仍旧返回false,则继续传递给父View的View处理。如此反复下去。
继续用武侠的经典例子:当宋青书发现来犯的敌人是成昆,他根本不是成昆的对手。他处理不了,也就是他的onTouchEvent返回false,于是就跑过去找宋远桥。宋远桥一听是成昆,他心里清楚,自己也不是对手,也就是onTouchEvent返回false,于是就去找张真人,张真人轻松拿捏成昆,onTouchEvent返回true.因此得出结论:如果onTouchEvent返回true,则处理了,不向上传递。如果onTouchEvent方法返回false,则不处理,继续向上传递。