🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
# 安卓事件传递机制 > 参考文章:[https://www.jianshu.com/p/238d1b753e64?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation](https://www.jianshu.com/p/238d1b753e64?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation "https://www.jianshu.com/p/238d1b753e64?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation") [](https://www.jianshu.com/p/238d1b753e64?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation)![image.png](https://upload-images.jianshu.io/upload_images/13971762-1594a6044e2eedc5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) ![image.png](https://upload-images.jianshu.io/upload_images/13971762-18aeeb969cd62cd0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) > DecorView属于View体系,当它调用super.dispatchTouchEvent()方法的时候,实际上是调用ViewGroup的dispatchTouchEvent()函数。 ``` //code View.java public boolean dispatchTouchEvent(MotionEvent event) { if (mInputEventConsistencyVerifier != null) { mInputEventConsistencyVerifier.onTouchEvent(event, 0); } if (onFilterTouchEventForSecurity(event)) { ListenerInfo li = mListenerInfo; if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED && li.mOnTouchListener.onTouch(this, event)) { return true; } if (onTouchEvent(event)) { return true; } } ... return false; } ``` > **在dispatchTouch()函数中,大致分成以下几个过程:** > > 1\. 函数会优先调用onFilterTouchEventForSecurity()方法对事件进行拦截。这个函数是在特定的界面模糊不可点击的情况下使用,一般我们不用理会。 > > 2\. View会获取OnTouchListener回调接口,并调用回调接口来处理事件。 > > 3\. 当回调接口不予处理的时候,将调用自己的onTouch()回调来处理 > > **所以对于View类来说,它的调用过程是:** dispatchTouch( )->OnTouchListener.onTouch( )->onTouch( ) ``` //code ViewGroup.java ... if (actionMasked == MotionEvent.ACTION_DOWN) { // Throw away all previous state when starting a new touch gesture. // The framework may have dropped the up or cancel event for the previous gesture // due to an app switch, ANR, or some other state change. cancelAndClearTouchTargets(ev); resetTouchState(); } ... ``` > 在刚开始执行dispatchTouch的时候,如果当前的事件是一个down事件,ViewGroup会清掉之前所保存的按下状态。调用的方法是cancelAndClearTouchTargets和resetTouchState。比如当前按钮处于按下状态,因为某种原因没有正常反弹,通过cancelAndClearTouchTargets就可以告诉按钮当前状态重置了,可以回弹了。之后,会执行ViewGroup的核心方法: ``` final boolean intercepted; if (actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null) { //判断是否可以执行onInterceptTouchEvent final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;//判断是否有必要执行onInterceptTouchEvent if (!disallowIntercept) { intercepted = onInterceptTouchEvent(ev); ev.setAction(action); // restore action in case it was changed } else { intercepted = false; } } else { // There are no touch targets and this action is not an initial down // so this view group continues to intercept touches. intercepted = true; } ``` > 这段代码的核心,在于是否调用onInterceptTouchEvent回调方法。一旦onInterceptTouchEvent方法返回true,意味着这个事件需要由当前ViewGroup来处理,也就是把ViewGroup当成View来看,走上述的View事件处理流程,在此不再赘述。那么什么时候调用这个回调方法呢? **ViewGroup的事件处理过程:** > dispatchTouch() -> onInterceptTouchEvent -> (View流程) OnTouchListener.onTouch( ) -> onTouch() ### 结论: * **当ViewGroup决定拦截事件后,后续事件将默认交给它处理并且不会再调用onInterceptTouchEvent方法来判断是否拦截。子View可以通过设置FLAG_DISALLOW_INTERCEPT标志位来不让ViewGroup拦截除ACTION_DOWN以外的事件。** * **所以我们知道了onInterceptTouchEvent并非每次都会被调用。如果要处理所有的点击事件那么需要选择dispatchTouchEvent方法,而FLAG_DISALLOW_INTERCEPT标志位可以帮助我们去有效的处理滑动冲突** * Android 事件分发总是遵循 Activity => ViewGroup => View 的传递顺序; * onTouch() 执行总优先于 onClick() > 以下图片来源:[https://www.jianshu.com/p/38015afcdb58](https://www.jianshu.com/p/38015afcdb58 "https://www.jianshu.com/p/38015afcdb58") **Activity 的事件分发示意图** ![image.png](https://upload-images.jianshu.io/upload_images/13971762-1fae1d7abca8cb60.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) **ViewGroup 事件分发示意图** ![image.png](https://upload-images.jianshu.io/upload_images/13971762-8e7982bda902dc68.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) **View 的事件分发示意图** ![image.png](https://upload-images.jianshu.io/upload_images/13971762-2c11f50b46c90b47.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) **事件分发工作流程总结** ![image.png](https://upload-images.jianshu.io/upload_images/13971762-b2ab59b9259cfa7a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)