原帖:Android事件分发机制详解:史上最全面、最易懂 - 简书
事件分发机制的主角
主角是谁呢?是点击事件,也叫touch事件。当用户触摸屏幕(View或ViewGroup派生的控件)将产生点击事件,Touch事件的相关细节(发生触摸的位置、时间等)被封装成MotionEvent对象
事件类型
从手指接触屏幕 至 手指离开屏幕,这个过程产生的一系列事件,大致过程如下:
即当一个点击事件(MotionEvent )产生后,系统需把这个事件传递给一个具体的 View去处理
事件分发的本质
将点击事件(MotionEvent)传递到某个具体的View 和 处理的整个过程就是分发过程
事件的传递
Activity、ViewGroup、View及其派生类组成
事件的分发顺序
一个点击事件发生后,事件先传到Activity,再传到ViewGroup,最终再传到View当中
事件分发过程中的协作方法
dispatchTouchEvent() —— 事件分发
onInterceptTouchEvent() —— 事件拦截
onTouchEvent() —— 事件响应
事件分发机制的分析
由于之前说的事件的分发顺序是Activity -》 ViewGroup -》View,也就是说要分别分析Activity对点击事件的分发机制,ViewGroup对点击事件的分发机制,View对点击事件的分发机制,下面开始一个一个的分析
Activity的分发机制
点击事件是DOWN意味着开始分发Activity中的事件,只要其中的getWindow.superDispatchTouchEvent返回true分发事件就结束了,而superDispatchTouchEvent返回的是顶层View(DecorView)的实例对象,而DecorView又是ViewGroup的子类,也就是说它实际调用了父类的方法也就是ViewGroup的dispatchTouchEvent(),这也实现了事件从Activity传到ViewGroup,至于ViewGroup为true/false就要看ViewGroup事件分发处理了,如果getWindow.superDispatchTouchEvent返回的是false,就进入onTouchEvent,该方法默认返回true,只有遇到处在边界外的消费事件才返回true,无论返回什么都结束Activity的事件分发
ViewGroup的分发机制
从Activity的事件分发我们可以知道ViewGroup分发机制从dispatchTouchEvent()开始
当你点击了某个控件时,就调用该控件所在的布局,用onInterceptTouchEvent来判断是否拦截事件,如果返回true或者无View接受事件,就不允许事件向子View传递调用ViewGroup的父类dispatchTouchEvent,ViewGroup的父类是View,所以调用的是View.dispatchTouchEvent,他自己处理该事件,调用了自身的onTouch,onTouch又调用了onTouchEvent,在onTouchEvent中performClick处理了该事件,如果返回了false,就允许事件继续向子View传递,遍历ViewGroup中所有子View找到相应的子View控件,调用子View的dispatchTouchEvent将ViewGroup中的事件传递给View
View的分发机制
从ViewGroup事件分发机制知道,View事件分发机制从dispatchTouchEvent()开始
当注册了监听器(mOnTouchListener 就不可能为 null),当前控件是否可以点击(由于很多View默认enable,故该条件恒定为true),mOnTouchListener.onTouch(this, event)如果该方法为true,三个条件为true后,View.dispatchTouchEvent()直接返回true,事件分发结束,如果返回false就会使得上述三个条件不全部成立,从而使得View.dispatchTouchEvent()中跳出If,执行onTouchEvent(event),在onTouchEvent(event)中,如果控件可以点击,一定返回true,否则返回false,用switch来判断点击的事件类型,是UP、DOWN、MOVE、CANCLE中的哪一个,加入是UP类型就调用performClick,再由其中的onClick为控件注册点击事件
总结
一般情况下,事件的分发都是由DOWN开始,调用Activity的dispatchTouchEvent,由这个方法向下传递事件给ViewGroup,一进ViewGroup就要判断是否用onInterceptTouchEvent拦截事件,不拦截就让传递给下层,下层的dispatchTouchEvent就会被调用,再问你是否拦截,直到事件被处理为止,拦截就将该事件交给当前View处理,也就是在onTouchEvent中处理点击事件,最后返回一个布尔值给dispatchTouchEvent告诉他是否已经处理,至此分发事件就到此结束了