android中的事件类型分为按键事件和屏幕触摸事件,Touch事件是屏幕触摸事件的基础事件,有必要对它进行深入的了解。
一个最简单的屏幕触摸动作触发了一系列Touch事件:ACTION_DOWN->ACTION_MOVE->ACTION_MOVE->ACTION_MOVE...->ACTION_MOVE->ACTION_UP
当屏幕中包含一个ViewGroup,而这个ViewGroup又包含一个子view,这个时候android系统如何处理Touch事件呢?到底是ViewGroup来处理Touch事件,还是子view来处理Touch事件呢?我只能很肯定的对你说不一定。呵呵,为什么呢?看看下面我的调查结果你就明白了。
android系统中的每个View的子类都具有下面三个和TouchEvent处理密切相关的方法:
1)public boolean dispatchTouchEvent(MotionEvent ev) 这个方法用来分发TouchEvent
2)public boolean onInterceptTouchEvent(MotionEvent ev) 这个方法用来拦截TouchEvent
3)public boolean onTouchEvent(MotionEvent ev) 这个方法用来处理TouchEvent
当TouchEvent发生时,首先Activity将TouchEvent传递给最顶层的View, TouchEvent最先到达最顶层 view 的 dispatchTouchEvent ,然后由 dispatchTouchEvent 方法进行分发,如果dispatchTouchEvent返回true ,则交给这个view的onTouchEvent处理,如果dispatchTouchEvent返回 false ,则交给这个 view 的 interceptTouchEvent 方法来决定是否要拦截这个事件,如果
interceptTouchEvent 返回 true ,也就是拦截掉了,则交给它的 onTouchEvent 来处理,如果 interceptTouchEvent 返回 false ,那么就传递给子 view ,由子 view 的 dispatchTouchEvent 再来开始这个事件的分发。如果事件传递到某一层的子 view 的 onTouchEvent 上了,这个方法返回了 false ,那么这个事件会从这个 view 往上传递,都是 onTouchEvent 来接收。而如果传递到最上面的 onTouchEvent
也返回 false 的话,这个事件就会“消失”,而且接收不到下一次事件。
通过语言描述这个处理逻辑很抽象,下面我就用代码来具体说明一下。
layout配置文件 main.xml
01 |
<?xml version="1.0" encoding="utf-8"?> |
02 |
<test.lzqdiy.MyLinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" |
03 |
android:orientation="vertical" |
04 |
android:layout_width="fill_parent" |
05 |
android:layout_height="fill_parent" |
06 |
android:gravity="center" > |
07 |
<test.lzqdiy.MyTextView |
08 |
android:layout_width="200px" |
09 |
android:layout_height="200px" |
10 |
android:id="@+id/tv" |
11 |
android:text="lzqdiy" |
12 |
android:textSize="40sp" |
13 |
android:textStyle="bold" |
14 |
android:background="#FFFFFF" |
15 |
android:textColor="#0000FF"/> |
16 |
</test.lzqdiy.MyLinearLayout> |
节点层次很简单,一个LinearLayout中添加了一个TextView。
下面是java代码:
001 |
package test.lzqdiy; |
002 |
003 |
import android.app.Activity; |
004 |
import android.os.Bundle; |
005 |
006 |
public class TestTouchEventApp extends Activity
{ |
007 |
/**
Called when the activity is first created. */ |
008 |
@Override |
009 |
public void onCreate(Bundle
savedInstanceState) { |
010 |
super.onCreate(savedInstanceState); |
011 |
setContentView(R.layout.main); |
012 |
} |
013 |
} |
014 |
package test.lzqdiy; |
015 |
016 |
import android.content.Context; |
017 |
import android.util.AttributeSet; |
018 |
import android.util.Log; |
019 |
import android.view.MotionEvent; |
020 |
import android.widget.LinearLayout; |
021 |
022 |
public class MyLinearLayout extends LinearLayout
{ |
023 |
private final String
TAG = "MyLinearLayout"; |
024 |
025 |
public MyLinearLayout(Context
context, AttributeSet attrs) { |
026 |
027 |
super(context,
attrs); |
028 |
029 |
Log.d(TAG,
TAG); |
030 |
031 |
} |
032 |
033 |
@Override |
034 |
public boolean dispatchTouchEvent(MotionEvent
ev) { |
035 |
int action
= ev.getAction(); |
036 |
037 |
switch (action)
{ |
038 |
039 |
case MotionEvent.ACTION_DOWN: |
040 |
041 |
Log.d(TAG, "dispatchTouchEvent
action:ACTION_DOWN"); |
042 |
043 |
break; |
044 |
045 |
case MotionEvent.ACTION_MOVE: |
046 |
047 |
Log.d(TAG, "dispatchTouchEvent
action:ACTION_MOVE"); |
048 |
049 |
break; |
050 |
051 |
case MotionEvent.ACTION_UP: |
052 |
053 |
Log.d(TAG, "dispatchTouchEvent
action:ACTION_UP"); |
054 |
055 |
break; |
056 |
057 |
case MotionEvent.ACTION_CANCEL: |
058 |
059 |
Log.d(TAG, "dispatchTouchEvent
action:ACTION_CANCEL"); |
060 |
061 |
break; |
062 |
063 |
} |
064 |
return super.dispatchTouchEvent(ev); |
065 |
} |
066 |
067 |
@Override |
068 |
public boolean onInterceptTouchEvent(MotionEvent
ev) { |
069 |
070 |
int action
= ev.getAction(); |
071 |
072 |
switch (action)
{ |
073 |
074 |
case MotionEvent.ACTION_DOWN: |
075 |
076 |
Log.d(TAG, "onInterceptTouchEvent
action:ACTION_DOWN"); |
077 |
078 |
break; |
079 |
080 |
case MotionEvent.ACTION_MOVE: |
081 |
082 |
Log.d(TAG, "onInterceptTouchEvent
action:ACTION_MOVE"); |
083 |
084 |
break; |
085 |
086 |
case MotionEvent.ACTION_UP: |
087 |
088 |
Log.d(TAG, "onInterceptTouchEvent
action:ACTION_UP"); |
089 |
090 |
break; |
091 |
092 |
case MotionEvent.ACTION_CANCEL: |
093 |
094 |
Log.d(TAG, "onInterceptTouchEvent
action:ACTION_CANCEL"); |
095 |
096 |
break; |
097 |
098 |
} |
099 |
100 |
return false; |
101 |
102 |
} |
103 |
104 |
@Override |
105 |
public boolean onTouchEvent(MotionEvent
ev) { |
106 |
107 |
int action
= ev.getAction(); |
108 |
109 |
switch (action)
{ |
110 |
111 |
case MotionEvent.ACTION_DOWN: |
112 |
113 |
Log.d(TAG, "---onTouchEvent
action:ACTION_DOWN"); |
114 |
115 |
break; |
116 |
117 |
case MotionEvent.ACTION_MOVE: |
118 |
119 |
Log.d(TAG, "---onTouchEvent
action:ACTION_MOVE"); |
120 |
121 |
break; |
122 |
123 |
case MotionEvent.ACTION_UP: |
124 |
125 |
Log.d(TAG, "---onTouchEvent
action:ACTION_UP"); |
126 |
127 |
break; |
128 |
129 |
case MotionEvent.ACTION_CANCEL: |
130 |
131 |
Log.d(TAG, "---onTouchEvent
action:ACTION_CANCEL"); |
132 |
133 |
break; |
134 |
135 |
} |
136 |
137 |
return true; |
138 |
} |
139 |
140 |
} |
141 |
package test.lzqdiy; |
142 |
143 |
import android.content.Context; |
144 |
import android.util.AttributeSet; |
145 |
import android.util.Log; |
146 |
import android.view.MotionEvent; |
147 |
import android.widget.TextView; |
148 |
149 |
public class MyTextView extends TextView
{ |
150 |
151 |
private final String
TAG = "MyTextView"; |
152 |
153 |
public MyTextView(Context
context, AttributeSet attrs) { |
154 |
155 |
super(context,
attrs); |
156 |
157 |
} |
158 |
159 |
@Override |
160 |
public boolean dispatchTouchEvent(MotionEvent
ev) { |
161 |
int action
= ev.getAction(); |
162 |
163 |
switch (action)
{ |
164 |
165 |
case MotionEvent.ACTION_DOWN: |
166 |
167 |
Log.d(TAG, "dispatchTouchEvent
action:ACTION_DOWN"); |
168 |
169 |
break; |
170 |
171 |
case MotionEvent.ACTION_MOVE: |
172 |
173 |
Log.d(TAG, "dispatchTouchEvent
action:ACTION_MOVE"); |
174 |
175 |
break; |
176 |
177 |
case MotionEvent.ACTION_UP: |
178 |
179 |
Log.d(TAG, "dispatchTouchEvent
action:ACTION_UP"); |
180 |
181 |
break; |
182 |
183 |
case MotionEvent.ACTION_CANCEL: |
184 |
185 |
Log.d(TAG, "onTouchEvent
action:ACTION_CANCEL"); |
186 |
187 |
break; |
188 |
189 |
} |
190 |
return super.dispatchTouchEvent(ev); |
191 |
} |
192 |
193 |
@Override |
194 |
public boolean onTouchEvent(MotionEvent
ev) { |
195 |
196 |
int action
= ev.getAction(); |
197 |
198 |
switch (action)
{ |
199 |
200 |
case MotionEvent.ACTION_DOWN: |
201 |
202 |
Log.d(TAG, "---onTouchEvent
action:ACTION_DOWN"); |
203 |
204 |
break; |
205 |
206 |
case MotionEvent.ACTION_MOVE: |
207 |
208 |
Log.d(TAG, "---onTouchEvent
action:ACTION_MOVE"); |
209 |
210 |
break; |
211 |
212 |
case MotionEvent.ACTION_UP: |
213 |
214 |
Log.d(TAG, "---onTouchEvent
action:ACTION_UP"); |
215 |
216 |
break; |
217 |
218 |
case MotionEvent.ACTION_CANCEL: |
219 |
220 |
Log.d(TAG, "---onTouchEvent
action:ACTION_CANCEL"); |
221 |
222 |
break; |
223 |
224 |
} |
225 |
226 |
return true; |
227 |
228 |
} |
229 |
230 |
} |
为了指代方便,下面将MyLinearLayout简称为L,将MyTextView简称为T,L.onInterceptTouchEvent=true 表示的含义为MyLinearLayout中的onInterceptTouchEvent方法返回值为true,通过程序运行时输出的Log来说明调用时序。
第1种情况 L.onInterceptTouchEvent=false&& L.onTouchEvent=true &&T.onTouchEvent=true 输出下面的Log:
D/MyLinearLayout(11865): dispatchTouchEvent action:ACTION_DOWN
D/MyLinearLayout(11865): onInterceptTouchEvent action:ACTION_DOWN
D/MyTextView(11865): dispatchTouchEvent action:ACTION_DOWN
D/MyTextView(11865): ---onTouchEvent action:ACTION_DOWN
D/MyLinearLayout(11865): dispatchTouchEvent action:ACTION_MOVE
D/MyLinearLayout(11865): onInterceptTouchEvent action:ACTION_MOVE
D/MyTextView(11865): dispatchTouchEvent action:ACTION_MOVE
D/MyTextView(11865): ---onTouchEvent action:ACTION_MOVE
...........省略其他的ACTION_MOVE事件Log
D/MyLinearLayout(11865): dispatchTouchEvent action:ACTION_UP
D/MyLinearLayout(11865): onInterceptTouchEvent action:ACTION_UP
D/MyTextView(11865): dispatchTouchEvent action:ACTION_UP
D/MyTextView(11865): ---onTouchEvent action:ACTION_UP
结论:TouchEvent完全由TextView处理。
第2种情况 L.onInterceptTouchEvent=false&& L.onTouchEvent=true &&T.onTouchEvent=false 输出下面的Log:
D/MyLinearLayout(13101): dispatchTouchEvent action:ACTION_DOWN
D/MyLinearLayout(13101): onInterceptTouchEvent action:ACTION_DOWN
D/MyTextView(13101): dispatchTouchEvent action:ACTION_DOWN
D/MyTextView(13101): ---onTouchEvent action:ACTION_DOWN
D/MyLinearLayout(13101): ---onTouchEvent action:ACTION_DOWN
D/MyLinearLayout(13101): dispatchTouchEvent action:ACTION_MOVE
D/MyLinearLayout(13101): ---onTouchEvent action:ACTION_MOVE
...........省略其他的ACTION_MOVE事件Log
D/MyLinearLayout(13101): dispatchTouchEvent action:ACTION_UP
D/MyLinearLayout(13101): ---onTouchEvent action:ACTION_UP
结论:TextView只处理了ACTION_DOWN事件,LinearLayout处理了所有的TouchEvent。
第3种情况 L.onInterceptTouchEvent=true&& L.onTouchEvent=true 输出下面的Log:
D/MyLinearLayout(13334): dispatchTouchEvent action:ACTION_DOWN
D/MyLinearLayout(13334): onInterceptTouchEvent action:ACTION_DOWN
D/MyLinearLayout(13334): ---onTouchEvent action:ACTION_DOWN
D/MyLinearLayout(13334): dispatchTouchEvent action:ACTION_MOVE
D/MyLinearLayout(13334): ---onTouchEvent action:ACTION_MOVE
...........省略其他的ACTION_MOVE事件Log
D/MyLinearLayout(13334): dispatchTouchEvent action:ACTION_UP
D/MyLinearLayout(13334): ---onTouchEvent action:ACTION_UP
结论:LinearLayout处理了所有的TouchEvent。
第4种情况 L.onInterceptTouchEvent=true&& L.onTouchEvent=false 输出下面的Log:
D/MyLinearLayout(13452): dispatchTouchEvent action:ACTION_DOWN
D/MyLinearLayout(13452): onInterceptTouchEvent action:ACTION_DOWN
D/MyLinearLayout(13452): ---onTouchEvent action:ACTION_DOWN
结论:LinearLayout只处理了ACTION_DOWN事件,那么其他的TouchEvent被谁处理了呢?答案是LinearLayout最外层的Activity处理了TouchEvent。
本文详细解析了Android中触摸事件的分发过程,包括按键事件和屏幕触摸事件,重点探讨了ViewGroup与子view间事件处理的逻辑,通过代码实例展示了事件传递的时序。
2343

被折叠的 条评论
为什么被折叠?



