首先是点击事件在不同的布局层次中传递的。
理解Down事件再哪个层次被消费(拦截),后续的Move、Up的点击事件如何传递。
其中ViewGroup中onInterceptTouchEvent方法用来对事件作预处理的,对于Down事件返回true表示要消费这个事件,不再向子View传递。
Android中dispatchTouchEvent, onInterceptTouchEvent, onTouchEvent的理解
onInterceptTouchEvent用于改变事件的传递方向。决定传递方向的是返回值,返回为false时事件会传递给子控件,返回值为true时事件会传递给当前控件的onTouchEvent(),这就是所谓的Intercept(拦截)。
[tisa ps:正确的使用方法是,在此方法内仅判断事件是否需要拦截,然后返回。即便需要拦截也应该直接返回true,然后由onTouchEvent方法进行处理。]
onTouchEvent用于处理事件,返回值决定当前控件是否消费(consume)了这个事件。尤其对于ACTION_DOWN事件,返回true,表示我想要处理后续事件;返回false,表示不关心此事件,并返回由父类进行处理。
可能你要问是否消费了又区别吗,反正我已经针对事件编写了处理代码?答案是有区别!比如ACTION_MOVE或者ACTION_UP发生的前提是一定曾经发生了ACTION_DOWN,如果你没有消费ACTION_DOWN,那么系统会认为ACTION_DOWN没有发生过,所以ACTION_MOVE或者ACTION_UP就不能被捕获。
在没有重写onInterceptTouchEvent()和onTouchEvent()的情况下(他们的返回值都是false), 对上面这个布局,MotionEvent事件的传递顺序如下:
基于以上点击事件的传递,可以重写一些ViewGroup,响应其拖动的事件,比如LinearLayout,重写其onInterceptTouchEvent()和onTouchEvent()两个方法可以达到效果(具体看实际布局中子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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
//true是拦截,false是不拦截。这里只是预处理判断点击的位置,不拦截。
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
int x = (
int) ev.getX();
int y = (
int) ev.getY();
dragSrcPointY = y;
FTLog.d(_TAG,
"x=" + x +
",y=" + y);
}
return
super.onInterceptTouchEvent(ev);
}
public boolean onTouchEvent(MotionEvent ev) {
//只有判断是点击触发拖动的区域时,才进行处理。
//否则不处理,交予FTBounceListView旧逻辑处理。
int action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
// FTLog.e("TMS===down==", "tms");
// bConsumeDown = true;
return
true;
// case MotionEvent.ACTION_MOVE:
// FTLog.e("TMS===move==", "tms");
// if (bConsumeDown == false)
// {
// super.onTouchEvent(ev);
// }
// break;
case MotionEvent.ACTION_UP:
FTLog.d(_TAG,
"x="+ev.getX()+
",y="+ev.getY());
if (ev.getY() < dragSrcPointY -
20)
{
//向上拖动距离超过20dip,才finish,动画效果。
try {
((Activity) context).finish();
((Activity) context).overridePendingTransition(
R.anim.move_bottom_in, R.anim.move_top_out);
}
catch (Exception e) {
e.printStackTrace();
}
}
return
true;
default:
break;
}
return
super.onTouchEvent(ev);
}
|
其他视具体情况而定,比如listview的最后一条,某中间区域响应拖动的事件:
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
|
//true是拦截,false是不拦截。这里只是预处理判断点击的位置,不拦截。
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
bConsumeDown =
false;
int x = (
int) ev.getX();
int y = (
int) ev.getY();
dragSrcPosition = pointToPosition(x, y);
dragSrcPointY = y;
if (dragSrcPosition == AdapterView.INVALID_POSITION) {
return
super.onInterceptTouchEvent(ev);
}
FTLog.d(_TAG,
"x=" + x +
",y=" + y);
FTLog.d(_TAG,
"dragSrcPosition==" + dragSrcPosition
+
"getAdapter().getCount()==" + getAdapter().getCount());
if (dragSrcPosition == getAdapter().getCount() -
1
|| dragSrcPosition == getAdapter().getCount() -
2)
{
// 最后一条是footer,倒数第二条是数据
ViewGroup itemView = (ViewGroup) getChildAt(dragSrcPosition
- getFirstVisiblePosition());
int itemLeft = itemView.getLeft();
int itemRight = itemView.getRight();
int itemMid = (itemRight + itemLeft) /
2;
FTLog.d(_TAG,
"itemLeft==" + itemLeft +
", itemRight="
+ itemRight +
",itemMid=" + itemMid);
if (x > itemMid -
60 && x < itemMid +
60) {
//预处理,判断是点击触发拖动的区域,并不拦截事件
bConsumeDown =
true;
return
false;
}
}
}
return
super.onInterceptTouchEvent(ev);
}
/**
* 触摸事件
*/
public boolean onTouchEvent(MotionEvent ev) {
if (bConsumeDown ==
true && dragSrcPosition != INVALID_POSITION) {
//只有判断是点击触发拖动的区域时,才进行处理。
//否则不处理,交予FTBounceListView旧逻辑处理。
int action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
// FTLog.e("TMS===down==", "tms");
// bConsumeDown = true;
break;
// case MotionEvent.ACTION_MOVE:
// FTLog.e("TMS===move==", "tms");
// if (bConsumeDown == false)
// {
// super.onTouchEvent(ev);
// }
// break;
case MotionEvent.ACTION_UP:
FTLog.d(_TAG,
"x="+ev.getX()+
",y="+ev.getY());
if (ev.getY() < dragSrcPointY -
20)
{
//向上拖动距离超过20dip,才finish,动画效果。
try {
((Activity) context).finish();
((Activity) context).overridePendingTransition(
R.anim.move_bottom_in,
R.anim.move_top_out);
}
catch (Exception e) {
e.printStackTrace();
}
}
break;
default:
break;
}
return
true;
}
return
super.onTouchEvent(ev);
}
|
以上重写ViewGroup的两个方法,对于具体的View来讲,可以setOnTouchLinstener方法,再其OnTouch方法中,用mGestureDetectorOpen.onTouchEvent(event);来响应。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
_imageview_room_op_item_open.setOnTouchListener(
new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
mGestureDetectorOpen.onTouchEvent(event);
return
true;
}
});
mGestureDetectorOpen =
new GestureDetector(
this,
new OnGestureListener()
{
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
//判断在_imageview_room_op_item_open控件上移动的距离,do something}
}
|