[转]Android Touch事件传递机制解析
android系统中的每个ViewGroup的子类都具有下面三个和TouchEvent处理密切相关的方法:
1)public boolean dispatchTouchEvent(MotionEvent ev) 这个方法用来分发TouchEvent
2)public boolean onInterceptTouchEvent(MotionEvent ev) 这个方法用来拦截TouchEvent
3)public boolean onTouchEvent(MotionEvent ev) 这个方法用来处理TouchEvent
注意:不是所有的View的子类,很多教程都说的是所有的View的子类,只有可以向里面添加View的控件才需要分发,比如TextView它本身就是最小的view了,所以不用再向它的子视图分发了,它也没有子视图了,所以它没有dispatch和Intercept,只有touchEvent。
![[转]Android Touch事件传递机制解析_1 [转]Android Touch事件传递机制解析_1](http://images.cnblogs.com/cnblogs_com/wipedata/492353/o_[%e8%bd%ac]Android%20Touch%e4%ba%8b%e4%bb%b6%e4%bc%a0%e9%80%92%e6%9c%ba%e5%88%b6%e8%a7%a3%e6%9e%90_1.png)
说明: 白色为最外层,它占满整个屏幕;
红色为中间区域,属于白色中的一层;
黑色为中心区域,必于红色中的一层。
注意:他们本质上是:LinearLayout,而不是RelativeLayout或者其它布局。
1.由中心区域处理touch事件
布局文件如下:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical"> <com.kris.touch.widget.TouchView android:id="@+id/view_out" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="#fff" android:gravity="center"> <com.kris.touch.widget.TouchView android:id="@+id/view_mid" android:layout_width="300px" android:layout_height="400px" android:background="#f00" android:gravity="center"> <com.kris.touch.widget.TouchView android:id="@+id/view_center" android:layout_width="150px" android:layout_height="150px" android:background="#000" android:gravity="center" android:clickable="true"> </com.kris.touch.widget.TouchView> </com.kris.touch.widget.TouchView> </com.kris.touch.widget.TouchView> </LinearLayout>
注意: android:clickable="true"
接下来我们看一下打印的日志:
![[转]Android Touch事件传递机制解析_2 [转]Android Touch事件传递机制解析_2](http://images.cnblogs.com/cnblogs_com/wipedata/492353/o_[%e8%bd%ac]Android%20Touch%e4%ba%8b%e4%bb%b6%e4%bc%a0%e9%80%92%e6%9c%ba%e5%88%b6%e8%a7%a3%e6%9e%90_2.png)
结合是上面的日志,我们可以看一下ACTION_DOWN事件处理流程:
![[转]Android Touch事件传递机制解析_3 [转]Android Touch事件传递机制解析_3](http://images.cnblogs.com/cnblogs_com/wipedata/492353/o_[%e8%bd%ac]Android%20Touch%e4%ba%8b%e4%bb%b6%e4%bc%a0%e9%80%92%e6%9c%ba%e5%88%b6%e8%a7%a3%e6%9e%90_3.png)
说明:
首先触摸事件发生时(ACTION_DOWN),由系统调用Activity的dispatchTouchEvent方法,分发该事件。根据触摸事件的坐标,将此事件传递给out的dispatchTouchEvent处理,out则调用onInterceptTouchEvent 判断事件是由自己处理,还是继续分发给子View。此处由于out不处理Touch事件,故根据事件发生坐标,将事件传递给out的直接子View(即middle)。
Middle及Center中事件处理过程同上。但是由于Center组件是clickable 表示其能处理Touch事件,故center中的onInterceptTouchEvent方法将事件传递给center自己的onTouchEvent方法处理。至此,此Touch事件已被处理,不继续进行传递。
2.没有指定谁会处理touch事件
布局文件如下:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical"> <com.kris.touch.widget.TouchView android:id="@+id/view_out" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="#fff" android:gravity="center"> <com.kris.touch.widget.TouchView android:id="@+id/view_mid" android:layout_width="300px" android:layout_height="400px" android:background="#f00" android:gravity="center"> <com.kris.touch.widget.TouchView android:id="@+id/view_center" android:layout_width="150px" android:layout_height="150px" android:background="#000" android:gravity="center"> </com.kris.touch.widget.TouchView> </com.kris.touch.widget.TouchView> </com.kris.touch.widget.TouchView> </LinearLayout>
注意:只是比上一次的布局少了android:clickable="true"
接下来我们看一下打印的日志
![[转]Android Touch事件传递机制解析_4 [转]Android Touch事件传递机制解析_4](http://images.cnblogs.com/cnblogs_com/wipedata/492353/o_[%e8%bd%ac]Android%20Touch%e4%ba%8b%e4%bb%b6%e4%bc%a0%e9%80%92%e6%9c%ba%e5%88%b6%e8%a7%a3%e6%9e%90_4.png)
结合是上面的日志,我们可以看一下ACTION_DOWN事件处理流程:
![[转]Android Touch事件传递机制解析_5 [转]Android Touch事件传递机制解析_5](http://images.cnblogs.com/cnblogs_com/wipedata/492353/o_[%e8%bd%ac]Android%20Touch%e4%ba%8b%e4%bb%b6%e4%bc%a0%e9%80%92%e6%9c%ba%e5%88%b6%e8%a7%a3%e6%9e%90_5.png)
说明:
事件处理流程大致同上,区别是此状态下,所有组件都不会处理事件,事件并不会被center的onTouchEvent方法“消费”,则事件会层层逆向传递回到Activity,若Activity也不对此事件进行处理,此事件相当于消失了(无效果)。
对于后续的move、up事件,由于第一个down事件已经确定由Activity处理事件,故up事有由Activity的dispatchTouchEvent直接分发给自己的onTouchEvent方法处理。
总结:
1) Touchevent 中,返回值是 true ,则说明消耗掉了这个事件,返回值是 false ,则没有消耗掉,会继续传递下去,这个是最基本的。
2) 事件传递的两种方式:
隧道方式:从根元素依次往下传递直到最内层子元素或在中间某一元素中由于某一条件停止传递。
冒泡方式:从最内层子元素依次往外传递直到根元素或在中间某一元素中由于某一条件停止传递。 android对Touch Event的分发逻辑是View从上层分发到下层(dispatchTouchEvent函数)类似于隧道方式,然后下层优先开始
处理Event(先mOnTouchListener,再onTouchEvent)并向上返回处理情况(boolean值),若返回true,则上层不再处理。类似于冒泡方式。
------- update 13.9.3 --------
Android事件传递机制【按键事件】
Android按键事件处理主要在View和Activity两个级别。和Touch事件相比,简单很多。
按键事件的处理机制如下:
1、默认情况下,如果没有View获得焦点,事件将传递给Activity处理。
2、如果View获得焦点,事件首先传递到View的回调方法中。view回调方法返回false,事件继续传递到Activity处理。反之,事件不会继续传递。

PS:使用View.SetFocusable(true)设置可以获得焦点。
需要注意的是:
1、按键的onKeyDown和onKeyUp是相互独立的,不会相互影响。
2、无论是View还是Activity中,建议重写事件回调方法时,只对处理过的按键返回true,没有处理的事件应该调用其父类方法。
否则,其他未处理事件不会被传递到合适的目标组件中,例如:Back按键失效问题。
转自:
http://www.cnblogs.com/jqyp/archive/2012/04/25/2469758.html
http://orgcent.com/android-key-event-mechanism/

浙公网安备 33010602011771号