一.滑动冲突的场景
当两个都可滑动的控件处于内外两层的关系时,这个时候我们往往会遇到滑动冲突的问题,比如最常见的ScrollView和ListView的冲突,就是最典型的一种滑动冲突场景
虽然能够滑动的控件五花八门,但万变不离其宗,滑动控件大致就分为两类,一类为上下滑动的,另一类即左右滑动的,既然这样那么滑动冲突的场景也是非常有限的。大致可以分为3类:
1.外部滑动和内部滑动方向不一致
2.外部滑动方向和内部滑动方向一致
3.这种情况可能会稍微复杂点,就是可能不止有两个滑动控件,冲突可能是上面两种情况的合集。
二.滑动冲突的解决办法
滑动冲突的场景虽然各不相同,上面也分析了3种典型的滑动冲突场景,但是解决滑动冲突是有固定套路的,
可以分为两种方式:
1.外部拦截法
外部拦截法就是所有点击事件都先经过父控件,如果父控件需要此点击事件就拦截,不需要就向下传递,
这样就可以解决滑动冲突了。外部拦截法就是覆写父控件的onInterceptTouchEvent()方法,
在此方法内做相应的处理即可。
代码如下:
@Override public boolean onInterceptTouchEvent(MotionEvent event) { boolean intercepted = false; int x = (int) event.getX(); int y = (int) event.getY(); switch (event.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; } mLastXIntercept = x; mLastYIntercept = y; return intercepted; }
这就是外部拦截法的典型逻辑,针对不同的滑动冲突只需要改写父控件需要当前点击事件的条件就可以了。
2.内部拦截法
内部拦截法是父控件不拦截任何事件,所有的事件都传递给子控件,如果子控件需要此点击事件,
就消耗掉,否则就交给父控件处理。内部拦截法首先需要覆写子控件的dispatchTouchEvent()方法。
代码如下:
@Override public boolean dispatchTouchEvent(MotionEvent event) { int x = (int) event.getX(); int y = (int) event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: parent.requestDisallowInterceptTouchEvent(true); break; case MotionEvent.ACTION_MOVE: int delX = x-mLastXIntercept; int delY = y-mLastXIntercept; if("父控件需要此点击事件"){ parent.requestDisallowInterceptTouchEvent(false); } break; case MotionEvent.ACTION_UP: break; default: break; } return super.dispatchTouchEvent(event); }
这就是内部拦截法的典型逻辑,针对不同的滑动冲突只需要改写父控件需要当前点击事件的条件就可以了。
内部拦截法除了覆写子控件的dispatchTouchEvent()方法,还需要覆写父控件的onInterceptTouchEvent()方法。
代码如下:
@Override public boolean onInterceptTouchEvent(MotionEvent event) { if(event.getAction()== MotionEvent.ACTION_DOWN){ return false; }else{ return true; } }
至此对于控件的滑动冲突无论是哪种滑动冲突,我们都可以选择合适的方法来得到解决了。