Android事件流程详解

网络上有不少博客讲述了android的事件分发机制和处理流程机制,但是看过千遍,总还是觉得有些迷迷糊糊,因此特地抽出一天事件来亲测下,向像我一样的广大入门程序员详细讲述android事件背后的故事,话不多说,上干货。

android整个事件流程主要牵扯到dispatchTouchEvent(),onInterceptTouchEvent(),

onTouchEvent()这三个方法,下表来说明这三个方法的功能和分布场景:

表1:

方法名称 功解解说 Activity ViewGroup View
dispatchTouchEvent() 事件分发 YES YES YES
onInterceptTouchEvent() 事件拦截 NO YES NO
onTouchEvent() 事件处理 YES YES YES

先来分析下Touch事件:所有Touch事件发生时会调用当前ActivitydispatchTouchEvent()方


法来分发事件,ActivitydispatchTouchEvent()方法最终会调用PhoneWindow类中的


superDispatchTouchEvent方法,最终逻辑就是该activity会调用ViewGroup类中的


dispatchTouchEvent()进行隧道式分发事件(按布局元素由外向内分发),如本案例中的分发流程


为TouchTraining-> TouchViewGroup -> TouchView,需要注意的是,当你在Activit中的


dispatchTouchEvent()中直接返回具体的布尔值(无论是true还是false),Touch事件直接会被


消费在该方法中,不会再进行下来的事件分发流程,因此必须在activity的dispatchTouchEvrent


返回super.dispatchTouchEvent()来进行事件分发流程。下面进行案例说明分析:


首先在定义自己的View和ViewGroup,重写表1它们各自支持的事件流程方法,我这里自定ViewGroup


继承的是LinearLayout(只要继承的是ViewGroup都一样),然后分别在Activity的布局文件中加入自定


义的控件,接着在Activity中也重写它支持的事件流程方法。


activity_touchtrain.xml

<com.training.cj.mytraining.view.TouchViewGroupxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="300dp"android:layout_height="300dp"android:background="@android:color/holo_green_dark"><com.training.cj.mytraining.view.TouchViewandroid:layout_width="150dp"android:layout_height="150dp"android:background="@android:color/holo_red_dark"/></com.training.cj.mytraining.view.TouchViewGroup>

wKioL1Yp00zxDMxQAAEKgDwoRMw917.jpg


TouchView(自定义View类)

@OverridepublicbooleandispatchTouchEvent(MotionEventevent){Log.e(TAG,"dispatchTouchEvent分发事件"+TouchEventUtil.getTouchAction(event.getAction()));returnsuper.dispatchTouchEvent(event);}@OverridepublicbooleanonTouchEvent(MotionEventev){Log.e(TAG,"onTouchEvent处理事件"+TouchEventUtil.getTouchAction(ev.getAction()));returnsuper.onTouchEvent(ev);}

TouchViewGroup(自定义ViewGroup类)

@OverridepublicbooleandispatchTouchEvent(MotionEventev){Log.e(TAG,"dispatchTouchEvent分发事件"+TouchEventUtil.getTouchAction(ev.getAction()));returnsuper.dispatchTouchEvent(ev);}@OverridepublicbooleanonInterceptTouchEvent(MotionEventev){Log.e(TAG,"onInterceptTouchEvent拦截事件"+TouchEventUtil.getTouchAction(ev.getAction()));returnsuper.onInterceptTouchEvent(ev);}@OverridepublicbooleanonTouchEvent(MotionEventev){Log.e(TAG,"onTouchEvent处理事件"+TouchEventUtil.getTouchAction(ev.getAction()));returnsuper.onTouchEvent(ev);}

TouchTraining(Activity)

@OverridepublicbooleandispatchTouchEvent(MotionEventev){Log.e(TAG,"dispatchTouchEvent分发事件"+TouchEventUtil.getTouchAction(ev.getAction()));returnsuper.dispatchTouchEvent(ev);}@OverridepublicbooleanonTouchEvent(MotionEventev){Log.e(TAG,"onTouchEvent处理事件"+TouchEventUtil.getTouchAction(ev.getAction()));returnsuper.onTouchEvent(ev);}

TouchEventUtils(工具类,获取当前事件类型)

publicstaticStringgetTouchAction(intactionId){StringactionName="Unknow:id="+actionId;switch(actionId){caseMotionEvent.ACTION_DOWN:actionName="ACTION_DOWN";break;caseMotionEvent.ACTION_MOVE:actionName="ACTION_MOVE";break;caseMotionEvent.ACTION_UP:actionName="ACTION_UP";break;caseMotionEvent.ACTION_CANCEL:actionName="ACTION_CANCEL";break;caseMotionEvent.ACTION_OUTSIDE:actionName="ACTION_OUTSIDE";break;}returnactionName;}


案例分析


方案1

条件
控件名称 dispatchTouchEvent返回值 onInterceptTouchEvent 返回值 onTouchEvent 返回值
TouchTraining
super.dispatchTouchEvent(ev) ---- super.onTouchEvent(ev)
TouchViewGroup false super.onInterceptTouchEvent(ev) super.onTouchEvent(ev)
TouchView super.dispatchTouchEvent(ev) ---- super.onTouchEvent(ev)

运行结果:

com.training.cj.mytraining E/TouchTraining: dispatchTouchEvent分发事件ACTION_DOWN

com.training.cj.mytraining E/TouchViewGroup: dispatchTouchEvent分发事件ACTION_DOWN

com.training.cj.mytraining E/TouchTraining: onTouchEvent处理事件ACTION_DOWN

com.training.cj.mytraining E/TouchTraining: dispatchTouchEvent分发事件ACTION_UP

com.training.cj.mytraining E/TouchTraining: onTouchEvent处理事件ACTION_UP


结果分析:Touch事件开始,调用TouchTraining的dispatchTouchEvent把事件分发TouchViewGroup

的dispatchTouchEvent,TouchViewGroup的dispatchTouchEvent返回false,事件停止向下传递,同

时事件并没有消费,但由于该事件来自TouchTraining(Activity),所以最终返回给TouchTraining

的onTouchEvent进行消费。


方案2

条件
控件名称 dispatchTouchEvent返回值 onInterceptTouchEvent 返回值 onTouchEvent 返回值
TouchTraining
super.dispatchTouchEvent(ev) ---- super.onTouchEvent(ev)
TouchViewGroup true super.onInterceptTouchEvent(ev) super.onTouchEvent(ev)
TouchView super.dispatchTouchEvent(ev) ---- super.onTouchEvent(ev)

运行结果:

com.training.cj.mytraining E/TouchTraining: dispatchTouchEvent分发事件ACTION_DOWN

com.training.cj.mytraining E/TouchViewGroup: dispatchTouchEvent分发事件ACTION_DOWN

com.training.cj.mytraining E/TouchTraining: dispatchTouchEvent分发事件ACTION_UP

com.training.cj.mytraining E/TouchViewGroup: dispatchTouchEvent分发事件ACTION_UP


结果分析:Touch事件由TouchTraining的dispatchTouchEvent不断向TouchViewGroup分发,

TouchViewGroup的dispatchTouchEvent返回true,TouchViewGroup在dispatchTouchEvent中不断消

费来自TouchTraining的dispatchTouchEvent分发的事件。


方案3

条件
控件名称 dispatchTouchEvent返回值 onInterceptTouchEvent 返回值 onTouchEvent 返回值
TouchTraining
super.dispatchTouchEvent(ev) ---- super.onTouchEvent(ev)
TouchViewGroup super.onInterceptTouchEvent(ev) true super.onTouchEvent(ev)
TouchView super.dispatchTouchEvent(ev) ---- super.onTouchEvent(ev)

运行结果:

com.training.cj.mytraining E/TouchTraining: dispatchTouchEvent分发事件ACTION_DOWN

com.training.cj.mytraining E/TouchViewGroup: dispatchTouchEvent分发事件ACTION_DOWN

com.training.cj.mytraining E/TouchViewGroup: onInterceptTouchEvent拦截事件ACTION_DOWN

com.training.cj.mytraining E/TouchViewGroup: onTouchEvent处理事件ACTION_DOWN

com.training.cj.mytraining E/TouchTraining: onTouchEvent处理事件ACTION_DOWN

com.training.cj.mytraining E/TouchTraining: dispatchTouchEvent分发事件ACTION_UP

com.training.cj.mytraining E/TouchTraining: onTouchEvent处理事件ACTION_UP


结果分析:Touch事件发生,调用TouchTraining的dispatchTouchEvent分发事件到TouchViewGroup

dispatchTouchEvent,TouchViewGroup的dispatchTouchEvent返回super.onInterceptTouchEvent(ev)进

行事件分发,事件向下传递给TouchViewGroup的onInterceptTouchEvent,TouchViewGroup的onInterceptTouchEvent返回true,事件被拦截并传递给TouchViewGroup的onTouchEvent进行消费,TouchViewGroup的onTouchEvent返回super.dispatchTouchEvent(ev),对Touch事件未消费并返回给上级控件的onTouchEvent进行消费,由于TouchViewGroup的Touch事件来自TouchTraining,所以最后 由TouchTraining的onTouchEvent进行消费。


方案4


条件
控件名称 dispatchTouchEvent返回值 onInterceptTouchEvent 返回值 onTouchEvent 返回值
TouchTraining
super.dispatchTouchEvent(ev) ---- super.onTouchEvent(ev)
TouchViewGroup super.onInterceptTouchEvent(ev) false super.onTouchEvent(ev)
TouchView super.dispatchTouchEvent(ev) ---- super.onTouchEvent(ev)


运行结果:

com.training.cj.mytraining E/TouchTraining: dispatchTouchEvent分发事件ACTION_DOWN

com.training.cj.mytraining E/TouchViewGroup: dispatchTouchEvent分发事件ACTION_DOWN

com.training.cj.mytraining E/TouchViewGroup: onInterceptTouchEvent拦截事件ACTION_DOWN

com.training.cj.mytraining E/TouchView: dispatchTouchEvent分发事件ACTION_DOWN

com.training.cj.mytraining E/TouchView: onTouchEvent处理事件ACTION_DOWN

com.training.cj.mytraining E/TouchViewGroup: onTouchEvent处理事件ACTION_DOWN

com.training.cj.mytraining E/TouchTraining: onTouchEvent处理事件ACTION_DOWN

com.training.cj.mytraining E/TouchTraining: dispatchTouchEvent分发事件ACTION_UP

com.training.cj.mytraining E/TouchTraining: onTouchEvent处理事件ACTION_UP


结果分析:Touch事件发生,调用TouchTraining的dispatchTouchEvent分发事件到TouchViewGroup的dispatchTouchEvent,TouchViewGroup的dispatchTouchEvent返回super.onInterceptTouchEvent(ev),继续分发向下传递事件到TouchViewGroup的onInterceptTouchEvent,TouchViewGroup的onInterceptTouchEvent返回false,继续分发向下传递事件到TouchView的dispatchTouchEvent,TouchView的dispatchTouchEvent返回super.dispatchTouchEvent(ev),继续分发向下传递事件到TouchView的onTouchEvent,TouchView的onTouchEvent返回super.onTouchEvent(ev),事件没有消费,返回给上级TouchViewGroup的onTouchEvent进行消费,TouchViewGroup的

onTouchEvent返回super.onTouchEvent(ev),继续返回给上级TouchTraining的onTouchEvent进行消费。


方案5:

条件
控件名称 dispatchTouchEvent返回值 onInterceptTouchEvent 返回值 onTouchEvent 返回值
TouchTraining
super.dispatchTouchEvent(ev) ---- super.onTouchEvent(ev)
TouchViewGroup super.onInterceptTouchEvent(ev) false super.onTouchEvent(ev)
TouchView true ---- super.onTouchEvent(ev)


运行结果:

com.training.cj.mytraining E/TouchTraining: dispatchTouchEvent分发事件ACTION_DOWN

com.training.cj.mytraining E/TouchViewGroup: dispatchTouchEvent分发事件ACTION_DOWN

com.training.cj.mytraining E/TouchViewGroup: onInterceptTouchEvent拦截事件ACTION_DOWN

com.training.cj.mytraining E/TouchView: dispatchTouchEvent分发事件ACTION_DOWN

com.training.cj.mytraining E/TouchView: onTouchEvent处理事件ACTION_DOWN

com.training.cj.mytraining E/TouchTraining: dispatchTouchEvent分发事件ACTION_UP

com.training.cj.mytraining E/TouchViewGroup: dispatchTouchEvent分发事件ACTION_UP

com.training.cj.mytraining E/TouchViewGroup: onInterceptTouchEvent拦截事件ACTION_UP

com.training.cj.mytraining E/TouchView: dispatchTouchEvent分发事件ACTION_UP

com.training.cj.mytraining E/TouchView: onTouchEvent处理事件ACTION_UP


结果分析:Touch事件发生,调用TouchTraining的dispatchTouchEvent分发事件到TouchViewGroup的dispatchTouchEvent,该方法返回super.dispatchTouchEvent(ev),继续分发事件到TouchViewGroup的onInterceptTouchEvent,该方法返回false,继续分发事件到TouchView的dispatchTouchEvent,该方法返回super.dispatchTouchEvent(ev),继续分发事件到onTouchEvent,由于onTouchEvent返回true,表示消费了事件,Touch事件终止。


好了,本期的Touch事件分析到这里就结束了,另外,还有一个小细节需要注意的是,在View和View Group中的onTouchEvent方法默认返回false,View Group中的onInterceptTouchEvent也默认返回false。所以上面5种方案描述出了所有的Touch事件传递可能。了解Touch事件的分发和消费机制,更有利于我们自定义控件,当然我们在自定义控件时,尽量不要重写dispatchTouchEvent这个方法。

本贴参考博客:http://www.cnblogs.com/sunzn/archive/2013/05/10/3064129.html


更多相关文章

  1. Android 获取蓝牙Mac地址的正确方法
  2. 分析方法论探讨
  3. Android学习之自定义控件之图片带文字的View
  4. android 程序开发的插件化 模块化方法 之二
  5. 关于“Android SDK manager中不出现完整Android版本安装包列表”
  6. Android注解式绑定控件,没你想象的那么难

随机推荐

  1. javascript 与 webview 交互
  2. Android限制EditText输入金额小于1E,并最
  3. Android(安卓)重写onCreateOptionsMenu后
  4. RK3288 android7.1.2 插 UVCCamera 摄像
  5. note_24:踩坑之安装android studio 3.3.2
  6. android 布局背景模糊化处理
  7. Android(安卓)加载本地图片 和 服务器图
  8. android使用分页标签
  9. Android中Intent的几种使用方法
  10. android框架结构