子View
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
|
<strong>
import
android.content.Context;
import
android.util.AttributeSet;
import
android.util.Log;
import
android.view.MotionEvent;
import
android.widget.Button;
import
android.widget.TextView;
public
class
MyTextView
extends
TextView {
private
static
final
String TAG =
"內嵌TextView"
;
public
MyTextView(Context context, AttributeSet attrs) {
super
(context, attrs);
}
public
MyTextView(Context context){
super
(context);
}
@Override
public
boolean
onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
System.out.println(
"TextView onTouchEvent Method is start&&"
);
if
(MotionEvent.ACTION_DOWN == event.getAction()){
Log.v(TAG +
" onTouchEvent:"
,
"ACTION_DOWN"
);
}
else
if
(MotionEvent.ACTION_MOVE == event.getAction()){
Log.v(TAG +
" onTouchEvent:"
,
"ACTION_MOVE"
);
}
else
{
Log.v(TAG +
" onTouchEvent:"
,
"ACTION_UP"
);
}
return
super
.onTouchEvent(event);
}
} </strong>
|
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
|
import
android.content.Context;
import
android.graphics.Color;
import
android.util.AttributeSet;
import
android.util.Log;
import
android.view.MotionEvent;
import
android.widget.LinearLayout;
public
class
MyLinearLayout1
extends
LinearLayout{
public
MyLinearLayout1(Context context, AttributeSet attrs) {
super
(context, attrs);
this
.setBackgroundColor(Color.WHITE);
}
public
MyLinearLayout1(Context context) {
super
(context);
this
.setBackgroundColor(Color.WHITE);
}
private
String TAG =
"第一层MyLinearLayout"
;
//該方法是用來分發觸摸事件的,確切說,應該是過濾觸摸事件的,如果return false的话,只能接收到DOWN事件,之后的比如MOVE、UP事件不会再继续接收.
@Override
public
boolean
dispatchTouchEvent(MotionEvent event){
System.out.println(
"dispatchTouchEvent method is start **"
);
if
(MotionEvent.ACTION_DOWN == event.getAction()){
Log.v(TAG +
"dispatchTouchEvent:"
,
"ACTION_DOWN"
);
}
else
if
(MotionEvent.ACTION_MOVE == event.getAction()){
Log.v(TAG +
"dispatchTouchEvent:"
,
"ACTION_MOVE"
);
}
else
{
Log.v(TAG +
"dispatchTouchEvent:"
,
"ACTION_UP"
);
}
super
.dispatchTouchEvent(event);
return
true
;
}
//該方法只會在dispatchTouchEvent調用了super.dispatchTouchEvent之後才會觸發。
//默認return false 只有return false子View才能接收到触摸事件
@Override
public
boolean
onInterceptTouchEvent(MotionEvent event){
System.out.println(
"onInterceptTouchEvent method is start##"
);
super
.onInterceptTouchEvent(event);
if
(MotionEvent.ACTION_DOWN == event.getAction()){
Log.v(TAG +
"onInterceptTouchEvent:"
,
"ACTION_DOWN"
);
}
else
if
(MotionEvent.ACTION_MOVE == event.getAction()){
Log.v(TAG +
"onInterceptTouchEvent:"
,
"ACTION_MOVE"
);
}
else
{
Log.v(TAG +
"onInterceptTouchEvent:"
,
"ACTION_UP"
);
}
return
false
;
}
//該方法是用來消耗觸摸事件的
//默認return false。return true 的話,就表示該事件已經處理結束。
@Override
public
boolean
onTouchEvent(MotionEvent event){
System.out.println(
"onTouchEvent method is start>>"
);
super
.onTouchEvent(event);
if
(MotionEvent.ACTION_DOWN == event.getAction()){
Log.v(TAG +
"onTouchEvent:"
,
"ACTION_DOWN"
);
}
else
if
(MotionEvent.ACTION_MOVE == event.getAction()){
Log.v(TAG +
"onTouchEvent:"
,
"ACTION_MOVE"
);
}
else
{
Log.v(TAG +
"onTouchEvent:"
,
"ACTION_UP"
);
}
return
true
;
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
<
com.testtouchevent.MyLinearLayout1
xmlns:android
=
"http://schemas.android.com/apk/res/android"
xmlns:tools
=
"http://schemas.android.com/tools"
android:id
=
"@+id/am_linear"
android:layout_width
=
"match_parent"
android:layout_height
=
"match_parent"
android:paddingBottom
=
"@dimen/activity_vertical_margin"
android:paddingLeft
=
"@dimen/activity_horizontal_margin"
android:paddingRight
=
"@dimen/activity_horizontal_margin"
android:paddingTop
=
"@dimen/activity_vertical_margin"
tools:context
=
".MainActivity"
>
<
com.testtouchevent.MyTextView
android:id
=
"@+id/am_tv"
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:text
=
"@string/hello_world"
android:textSize
=
"50sp"
/>
</
com.testtouchevent.MyLinearLayout1
>
|
一、
| 是否調用super | return |
|
dispatchTouchEvent |
| true |
|
onInterceptTouchEvent | super | true |
|
onTouchEvent | super | true |
|
|
|
|
|
二、
| 是否調用super | return |
|
dispatchTouchEvent |
| false |
|
onInterceptTouchEvent | super | true |
|
onTouchEvent | super | true |
|
也就是說如果dispatchTouchEvent返回的是false,就不在接收接下來一系列觸摸事件的處理了。而且沒調用super,也不會將event傳遞到另外兩個方法。
三、
| 是否調用super | return |
|
dispatchTouchEvent | super | true |
|
onInterceptTouchEvent | super | true |
|
onTouchEvent | super | true |
|
调用了 dispatchTouchEvent方法中调用了 super.dispatchTouchEvent()后,另外的两个方法才得以调用。
其中只 dispatchTouchEvent return false:
同樣的不會處理down之後的事件,但是會將其給後面的兩個方法。
其中只 onInterceptTouchEvent return false
四、在ViewGroup中添加子View,並且設置了onClick之後:
1)
是否調用super
return
dispatchTouchEvent
super
false
onInterceptTouchEvent
super
false
onTouchEvent
super
false
只接收down事件。之後的就不會再接收了。也就沒有點擊事件的處理情況,因為點擊的處理實在up之後進行的
2)
1、
dispatchTouchEvent return true:
onInterceptTouchEvent return false:
onTouchEvent return false;
2、
dispatchTouchEvent return true:
onInterceptTouchEvent return true:
onTouchEvent return false;
可以看到事件沒有分發給子view,這時如果LinearLayout也有觸摸的處理事件的話,比如Click那麼:
也就是說,LinearLayout會響應點擊事件
3、
dispatchTouchEvent return true:
onInterceptTouchEvent return false:
onTouchEvent return false;
相比較2例子而言,如果onInterceptTouchEvent return 的是false 那麼會先向下傳遞,最終TextView會得到事件的最終處理權。
4、
dispatchTouchEvent return true:
onInterceptTouchEvent return false:
onTouchEvent return true;
可見向下傳遞後,子View處理完Click事件後,點擊事件已經消耗,所以LinearLayout不會在有點擊事件的響應。
5、
dispatchTouchEvent return true:
onInterceptTouchEvent return true:
onTouchEvent return true;
反正不會再向下傳遞,子view獲取不到事件了,所以onTouchEvent返回什麼就沒什麼大的關係了。
上面的例子都是子View的onTouchEvent return super.onTouchEvent(event); 下面我們手動的改一下讓他return false or true
6、子view onTouchEvent return 的是false
dispatchTouchEvent return true:
onInterceptTouchEvent return false:
onTouchEvent return true;//false
執行了Activity中LinearLayout的點擊事件
7、子view onTouchEvent return 的是true
dispatchTouchEvent return true:
onInterceptTouchEvent return false:
onTouchEvent return true;//false
沒有執行Activity中TextView的點擊事件。
总结
以上的几种情况就是我们经常遇到的了,总结起来有几个重要的点 :
1、如果Parent ViewGroup的onInterceptTouchEvent返回false, 并且触摸的目标view对于触摸事件的处理结果返回的是true,那么后续事件会先经过parent 的onInterceptTouchEvent, 然后再交给目标view进行处理;
2、如果Parent ViewGroup的onInterceptTouchEvent返回true,即对事件进行拦截,那么事件将不会再经过onInterceptTouchEvent,而是直接进入到onTouchEvent进行处理;如果onTouchEvent返回true,则表示该事件被处理了;如果返回FALSE,则代表事件没有被处理,那么事件会被上交给它的parent来处理,如果没有parent来处理,那么最终会交给Activity来处理;
3、如果用户在触摸的某个事件才拦截,那么目标view会收到一个CANCEL事件,然后后续的事件不会再交给目标view,而被转交给Parent的onTouchEvent方法进行处理。比如情景6当中,在TouchLayout的DOWN时不对事件进行拦截,这时事件会被TouchTv正常处理。但是在MOVE时事件被拦截了,此时TouchTv收到了一个CANCEL事件,MOVE以及后续的事件就交给了TouchLayout进行处理。