事件分发机制的理解

221 阅读3分钟

事件:当手指触摸屏幕系统会做出一系列响应,会把这些响应封装成一个个的MotionEvent对象,事件分发机制说白了就是这些MotionEvent对象在UI界面里的传递机制;

常见的事件:ACTION_DOWN(手指按下),ACTION_MOVE(手指在屏幕上滑动),ACTION_UP(手指离开屏幕),ACTION_CANCEL(一系列事件,前驱事件被view处理,但后面事件被父view拦截);

事件传递机制基本:事件产生后首先传递给Activity,然后依次向下分发: Activity—>Phonewindow—>DecorView—>ViewGroup—>View;而事件的处理流程则和分发流程相反,即:View—>ViewGroup—>DecorView—>PhoneWindow—>Activity。 整体来说事件分发机制涉及三个主体,View,ViewGroup,Activity

事件分发机制涉及方法:DispatchTouchevent:事件分发机制的核心,所有事件调度都是它负责。返回值为boolean,一般我们不会处理,默认向下传递。三个主体都有这个方法;Activity和ViewGroup用它向下分发事件,view用它负责onClick,onLongClick,onTouch,onTouchEvent的事件分发;

onInterceptTouchEvent:只有ViewGroup有这个方法,表示是否拦截,如果拦截则事件不会再向它的子View传递,转而调用它的onTouchEvent方法;Activity和View没这个方法。返回值为boolean,为true表示拦截,false则不拦截。前者是事件的起始,如果拦截,那么整个页面无响应,不合理。后者属于事件分发的最末短,没必要拦截,只需要调用onTouchEvent判断是否处理事件即可;

onTouchEvent:三个主体都有这个方法,返回值boolean类型,如果为true表示消费事件,false则不消费。

事件传递机制详细:事件产生后调用Activity的dispatchTouchEvent向下分发。然后到ViewGroup,调用ViewGroup的dispatTouchchEvent方法,再调用onInterceptTouchEvent,如果该方法返回false则事件会继续向下传递到view,如果该方法返回true,表示拦截事件。事件被拦截后就交给viewgroup的ontouchevent去处理事件,如果ontouchevent返回false,则事件交给activity的ontouchevent处理,如果viewgroup的ontouchevent返回true,则事件被消费,viewgroup的dispatchtouchevent返回true,activity的dispatchtouchevent返回true,结束。如果viewgroup没拦截事件,则会调用view的dispatchtouchevent方法,然后调用view的ontouchevent方法,如果该方法返回true,则表示消费事件,view的dispatchtouchevent返回true,viewgroup的dispatchtouchevent返回true,activity的dispatchtouchevent返回true,结束。如果view的ontouchevent返回false,表示不消费该事件,则事件向上传递给viewgroup,类似分析,如果viewgroup也不消费事件,则事件最终会丢给activity处理。

对view的onclick,onlonhclick,ontouch,ontouchevent执行顺序的理解:onclick包含两个事件,ACTIONdown和ACTIONup,一定处于最末,因为不可能等待;onlonhclick包含ACTIONdown但有时间要求,处于倒数第二执行;ontouch是用户自定义的,优先级要高于ontouchevent这个系统默认;综上他们的排序为 ontouch—>ontouchevent—>onlongclick—>onclick

对view重叠响应事件的理解:当点击到两个view重叠区域,上层和下层来区分。1.如果下层可点击,上层不可点击,那么还是下层响应事件;2.如果上层可点击,下层不可点击,那么上层响应事件;3.如果都可点击,则上层响应事件,消费事件,下层接收不到事件。

事件消费的理解:1.ontouchevent方法返回true表示消费这个事件,2.不论 View 自身是否注册点击事件,只要 View 是可点击的(android:onclickable=true)就会消费事件。

一个系列事件都应该被同一view消费的理解:防止事件响应混乱。ViewGroup 里面用了一个成员变量 mFirstTouchTarget 来保存消费事件的子 View 信息,因为安卓是支持多指操作的,所以这个 mFirstTouchTarget 是一个 TouchTarget 的链表。在View 的 dispatchTouchEvent 可以分为三个阶段:判断是否需要拦截;分发事件找到消费事件的子 View,更新到 mFirstTouchTarget;根据是否拦截和 mFirstTouchTarget 再次分发事件。