滑动冲突三种情况
o 外部滑动方式与内部滑动方式不一样.
o 外部滑动方式与内部滑动方式一致.
o 上面两种情况的嵌套.
滑动冲突处理原则
对于上面的第一种情况
记录上次记录点减去当前点得到deltaX
,deltaY
o 可以利用滑动路径和水平方向所形成的夹角来确定是那种滑动,如果小于45°,那自然就是横向,大于就是纵向.
o 可以对比横向滑动距离和纵向滑动距离,那个大就是那个方向滑动距离大.
对于第二,三种情况
可以 根据业务写出处理规则, 比如当内部View滑动到顶部或者底部时响应外部View,我们就可以根据这个规则判断内部View有没有滑动到底, 如果有的话就不消费事件,没有的话就消费事件.具体怎么消费事件有两种方法.
外部拦截法
所有的事件都要经由decorView分发,所以我们可以在decorView处做文章
如果父View需要事件,就拦截事件;否则就不拦截事件.具体实现在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 | public boolean onInterceptTouchEvent(MotionEvent event){ boolean interceptd = false; //获取当前动作所在点 int x = (int) event.getX(); int y = (int) event.getY(); switch(event.getAction()){ case MotionEvent.ACTION_DOWN: //默认不拦截ACTION_DOWN,因为父View一旦拦截ACTION_DOWN,那么这个系列的事件都会交由它处理. interceptd = false; break; case MotionEvent.ACTION_MOVE: if(父容器需要当前点击事件){ interceptd = true; }else{ interceptd = false; } break; case MotionEvent.ACTION_UP: //默认不拦截ACTION_UP,因为子View如果响应当前系列事件没有ACTION_UP的话无法触发onClick()方法 interceptd = false; break; default: break; } //保存最后一个拦截点 mLastXIntercept = x; mLastYIntercept = y; return interceptd; } |
内部拦截法
父容器默认不拦截任何事件,所有事件都交由子元素,子元素不需要再requestDisallowInterceptTouchEvent(boolean)
操控父元素处理,和上面的方法正好相反.
Called when a child does not want this parent and its ancestors to intercept touch events with onInterceptTouchEvent(MotionEvent).
disallowIntercept(boolean)
boolean: True if the child does not want the parent to intercept touch events.
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 | public boolean dispatchTouchEvent(MotionEvent event){ //获取当前点位置 int x = (int) event.getX(); int y = (int) event.getY(); switch(event.getAction()){ case MotionEvent.ACTION_DOWN: /** 操控父元素不拦截ACTION_DOWN,因为ACTION_DOWN不受 ACTION_DISALLOW_INTERCEPT 标记控制,所以一旦父元素拦截ACTION_DOWN,这个事件系列都会被交由父元素处理. */ parent.requestDisallowInterceptTouchEvent(true); break; case MotionEvent.ACTION_MOVE: int deltaX = X - mLastX; int deltaY = Y - mLastY; if(父容器需要此类事件){ //让父元素可以继续拦截MOVE事件 parent.requestDisallowInterceptTouchEvent(false); } break; case MotionEvent.ACTION_UP: break; default: break; } mLastX = x; mLastY = y; return super.dispatchTouchEvent(event); } |
父元素要做出如下处理
1 2 3 4 5 6 7 8 | public boolean onInterceptTouchEvent(MotionEvent event){ int action = event.getAction(); if(action == MotionEvent.ACTION_DOWN){ return false; }else{ return true; } } |
默认拦截除了ACTION_DOWN
以外的事件.这样子元素调用requestDisallowInterceptTouchEvent(false)
父元素才能继续拦截所需事件???
拦截方法对比
拦截方法 | 内部拦截法 | 外部拦截法 |
定义 | 父元素不拦截任何事件,所有事件都传给子元素 | 父元素需要就直接拦截,不需要就不拦截 |
重写 | decorView的 | 子View的 |
默认 | decorView不拦截 | 子元素默认拦截 |