View事件分发的反思

Activity的dispatchTouchEvent(MotionEvent ev)和onTouchEvent(MotionEvent ev)方法的来源引发的思考,本文不侧重于讲解View事件的分发机制!不当之处,请及时指出,谢谢。

问题

  • 在Activity override的方法中,存在的onTouchEvent(MotionEvent ev)和dispatchTouchEvent(MotionEvent ev)来源是哪里?

View事件分发机制回顾

Android界面是有View和ViewGroup构成的。正如大家所了解的一样:View和ViewGroup的事件分发机制有部分的差别。

事件序列是指从手指触碰屏幕的那一刻起,到手指离开屏幕那一刻结束,在这个过程中产生的一系列事件,以down事件开始,中间含有数量不定的move事件,最终以up事件结束。

dispatchTouchEvent(MotionEvent ev)
用来进行事件的分发,如果时间传递到当前的View,那么此方法一定会被调用,返回的结果受当前View的onTouchEvent和下级view的dispatchTouchEvent方法影响。

onInterceptTouchEvent(MotionEvent ev)
View没有此方法,所以一旦有点击事件传递给它,那么它的OnTouchEvent方法就会被调用。ViewGroup中,在接收到dispatchTouchEvent后,在其内部会调用此方法,用来判断是否拦截当前事件,如果拦截,那么在同一个事件序列中,此方法不会被调用。

onTouchEvent(MotionEvent ev)
在dispatchTouchEvent方法中调用,用来处理点击事件,返回结果表示是否消耗当前事件,如果不消耗,则无法z再次接受当前事件序列。

解决问题

正如了解到的事件发生首先传递给当前的Activity,由Activity的dispatchTouchEvent,来进行分发。那么我们来查看Actvity中的dispatchTouchEvent方法,Activity源码如下图:

通过源码查看发现,Activity调用的是Window中的dispatchTouchEvent方法。接着查找OnTouchEvent


透过源码问题1的答案,显而易见了,activity的onTouchEvent和dispatchTouchEvent来源与window。

那么window又是如何处理的呢?

通过源码我们发现window是抽象类,同时他的superDispatchTouchEvent也是抽象方法,如图

那么我们就需要找到他的实现类,通过查看Window源码发现,它只有一个实现类为PhoneWindow,如图

其实window是通过View的形式展现的,一个window对应这一个View和ViewRootImpl,如果有兴趣可以查看源码,这里不做叙述,收。

接着上面我们查找PhoneWindow中的superDispatchTouchEvent方法如图

发现PhoneWindow调用的是mDecor,即DecorView.也就是说PhoneWindow将事件直接传递给了DecorView,那么我们接着了解下DecorView


通过源码发现DecorView为顶级View即界面的根布局,同时由于DecorView继承自FrameLayout,而且是根布局,所以最终的事件会分发到界面中的根布局(DecorView),然后由根布局向我们添加的View分发,至此,Touch事件完美的分发下去了。

最后:本文不侧重与探讨View事件的分发机制。旨在分享遇到问题时的解决方案。That`s All! 文章若有不当之处,请及时指出,谢谢!