界面中的内外两层同时可以滑动,就会产生滑动冲突。
常见场景
- 外部滑动方向和内部滑动方向不一致;
- 外部滑动方向和内部滑动方向一致;
- 前面两种情况的嵌套;
滑动冲突处理规则
场景一,根据滑动的方向,来判断究竟是父控件进行拦截还是子控件进行拦截;
场景二,根据业务需求进行判断,什么时候父控件进行拦截,什么时候子控件进行拦截;
场景三,情况复杂,同样根据需求在业务上寻找突破点;
补充:可以根据横向滑动距离和纵向滑动距离的差值,来判断究竟是横向滑动还是纵向滑动
具体的解决方法
外部拦截法
所谓外部拦截法就是所有的点击事件都要经过父容器,如果父容器需要处理就进行拦截,如果不需要处理就不拦截,交给子控件进行处理,外部拦截法需要重写父容器的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 35
| int 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开发艺术探索》
上一篇:MeasureSpec
下一篇:Canvas的裁剪