Android中Touch事件的处理逻辑

来源:互联网 发布:linux已安装软件位置 编辑:程序博客网 时间:2024/05/22 17:37
From: http://www.oschina.net/question/163910_27289
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
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xmlversion="1.0"encoding="utf-8"?>
<test.lzqdiy.MyLinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:gravity="center">
       <test.lzqdiy.MyTextView
            android:layout_width="200px"
            android:layout_height="200px"
            android:id="@+id/tv"
            android:text="lzqdiy"
            android:textSize="40sp"
            android:textStyle="bold"
            android:background="#FFFFFF"
            android:textColor="#0000FF"/>
</test.lzqdiy.MyLinearLayout>
节点层次很简单,一个LinearLayout中添加了一个TextView。

下面是java代码:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
package test.lzqdiy;
 
import android.app.Activity;
import android.os.Bundle;
 
public class TestTouchEventApp extendsActivity {
    /** Called when the activity is first created. */
    @Override
    publicvoid onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
}
packagetest.lzqdiy;
 
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.LinearLayout;
 
public class MyLinearLayout extendsLinearLayout {
    privatefinal String TAG = "MyLinearLayout";
 
    publicMyLinearLayout(Context context, AttributeSet attrs) {
 
        super(context, attrs);
 
        Log.d(TAG, TAG);
 
    }
 
    @Override
    publicboolean dispatchTouchEvent(MotionEvent ev) {
        intaction = ev.getAction();
 
        switch(action) {
 
        caseMotionEvent.ACTION_DOWN:
 
            Log.d(TAG,"dispatchTouchEvent action:ACTION_DOWN");
 
            break;
 
        caseMotionEvent.ACTION_MOVE:
 
            Log.d(TAG,"dispatchTouchEvent action:ACTION_MOVE");
 
            break;
 
        caseMotionEvent.ACTION_UP:
 
            Log.d(TAG,"dispatchTouchEvent action:ACTION_UP");
 
            break;
 
        caseMotionEvent.ACTION_CANCEL:
 
            Log.d(TAG,"dispatchTouchEvent action:ACTION_CANCEL");
 
            break;
 
        }
        returnsuper.dispatchTouchEvent(ev);
    }
 
    @Override
    publicboolean onInterceptTouchEvent(MotionEvent ev) {
 
        intaction = ev.getAction();
 
        switch(action) {
 
        caseMotionEvent.ACTION_DOWN:
 
            Log.d(TAG,"onInterceptTouchEvent action:ACTION_DOWN");
 
            break;
 
        caseMotionEvent.ACTION_MOVE:
 
            Log.d(TAG,"onInterceptTouchEvent action:ACTION_MOVE");
 
            break;
 
        caseMotionEvent.ACTION_UP:
 
            Log.d(TAG,"onInterceptTouchEvent action:ACTION_UP");
 
            break;
 
        caseMotionEvent.ACTION_CANCEL:
 
            Log.d(TAG,"onInterceptTouchEvent action:ACTION_CANCEL");
 
            break;
 
        }
 
        returnfalse;
 
    }
 
    @Override
    publicboolean onTouchEvent(MotionEvent ev) {
 
        intaction = ev.getAction();
 
        switch(action) {
 
        caseMotionEvent.ACTION_DOWN:
 
            Log.d(TAG,"---onTouchEvent action:ACTION_DOWN");
 
            break;
 
        caseMotionEvent.ACTION_MOVE:
 
            Log.d(TAG,"---onTouchEvent action:ACTION_MOVE");
 
            break;
 
        caseMotionEvent.ACTION_UP:
 
            Log.d(TAG,"---onTouchEvent action:ACTION_UP");
 
            break;
 
        caseMotionEvent.ACTION_CANCEL:
 
            Log.d(TAG,"---onTouchEvent action:ACTION_CANCEL");
 
            break;
 
        }
 
        returntrue;
    }
 
}
packagetest.lzqdiy;
 
importandroid.content.Context;
importandroid.util.AttributeSet;
importandroid.util.Log;
importandroid.view.MotionEvent;
importandroid.widget.TextView;
 
publicclass MyTextView extends TextView {
 
    privatefinal String TAG = "MyTextView";
 
    publicMyTextView(Context context, AttributeSet attrs) {
 
        super(context, attrs);
 
    }
 
    @Override
    publicboolean dispatchTouchEvent(MotionEvent ev) {
        intaction = ev.getAction();
 
        switch(action) {
 
        caseMotionEvent.ACTION_DOWN:
 
            Log.d(TAG,"dispatchTouchEvent action:ACTION_DOWN");
 
            break;
 
        caseMotionEvent.ACTION_MOVE:
 
            Log.d(TAG,"dispatchTouchEvent action:ACTION_MOVE");
 
            break;
 
        caseMotionEvent.ACTION_UP:
 
            Log.d(TAG,"dispatchTouchEvent action:ACTION_UP");
 
            break;
 
        caseMotionEvent.ACTION_CANCEL:
 
            Log.d(TAG,"onTouchEvent action:ACTION_CANCEL");
 
            break;
 
        }
        returnsuper.dispatchTouchEvent(ev);
    }
 
    @Override
    publicboolean onTouchEvent(MotionEvent ev) {
 
        intaction = ev.getAction();
 
        switch(action) {
 
        caseMotionEvent.ACTION_DOWN:
 
            Log.d(TAG,"---onTouchEvent action:ACTION_DOWN");
 
            break;
 
        caseMotionEvent.ACTION_MOVE:
 
            Log.d(TAG,"---onTouchEvent action:ACTION_MOVE");
 
            break;
 
        caseMotionEvent.ACTION_UP:
 
            Log.d(TAG,"---onTouchEvent action:ACTION_UP");
 
            break;
 
        caseMotionEvent.ACTION_CANCEL:
 
            Log.d(TAG,"---onTouchEvent action:ACTION_CANCEL");
 
            break;
 
        }
 
        returntrue;
 
    }
 
}
为了指代方便,下面将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。

好累啊!终于完成了,写得比较仓促,难免有不妥之处,请博友们指正。

0 0