滑动冲突的处理
界面中的内外两层同时可以滑动,就会产生滑动冲突。
常见场景
- 外部滑动方向和内部滑动方向不一致;
- 外部滑动方向和内部滑动方向一致;
- 前面两种情况的嵌套;
滑动冲突处理规则
场景一,根据滑动的方向,来判断究竟是父控件进行拦截还是子控件进行拦截;
场景二,根据业务需求进行判断,什么时候父控件进行拦截,什么时候子控件进行拦截;
场景三,情况复杂,同样根据需求在业务上寻找突破点;
补充:可以根据横向滑动距离和纵向滑动距离的差值,来判断究竟是横向滑动还是纵向滑动
具体的解决方法
外部拦截法
所谓外部拦截法就是所有的点击事件都要经过父容器,如果父容器需要处理就进行拦截,如果不需要处理就不拦截,交给子控件进行处理,外部拦截法需要重写父容器的onInterceptTouchEvent方法,伪代码如下: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 private int mLastX = 0;
private int mLastY = 0;
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
int x = (int) ev.getX();
int y = (int) ev.getY();
boolean intercepted = false;
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
intercepted = false;
break;
case MotionEvent.ACTION_MOVE:
if ("父容器需要进行拦截") {
intercepted = true;
} else {
intercepted = false;
}
break;
case MotionEvent.ACTION_UP:
intercepted = false;
break;
default:
break;
}
mLastX = x;
mLastY = y;
return intercepted;
}
内部拦截法
所谓内部拦截法就是父容器不拦截任何的点击事件,所有的点击事件都交给子View进行处理,如果子View,需要拦截的话就消耗事件,不需要拦截的话就将事件交给父容器进行处理,内部拦截法需要配合requestDisallowInterceptTouchEvent方法进行处理。内部拦截法需要重写子View的dispatchTouchEvent方法和父容器的onInterceptTouchEvent方法进行处理。伪代码如下所示:
子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
35int mLastX = 0;
int mLastY = 0;
ViewGroup parent;
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
int x = (int) ev.getX();
int y = (int) ev.getY();
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
parent.requestDisallowInterceptTouchEvent(true);
break;
case MotionEvent.ACTION_MOVE:
int deltaX = x - mLastX;
int deltaY = y - mLastY;
if ("父容器需要处理事件") {
parent.requestDisallowInterceptTouchEvent(false);
}
break;
case MotionEvent.ACTION_UP:
break;
default:
break;
}
return super.dispatchTouchEvent(ev);
}
父容器:1
2
3
4
5
6
7
8
9
10
11
12
13
14@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean intercepted = false;
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
intercepted = false;
} else {
intercepted = true;
}
return intercepted;
}
}
父容器不拦截DOWN事件,默认拦截DOWN事件之外的其他事件,这样当子元素调用parent.requestDisallowInterceptTouchEvent(false)方法时,父元素才能继续拦截所需的事件。
参考资料:
《Android开发艺术探索》