view的滑动冲突解决方案
一、常见的滑动冲突场景
1.外部滑动方向和内部滑动方向不一致
2.外部滑动方向和内部滑动方向一致
3.上面两种情况的嵌套
二、滑动冲突处理的原则
场景1的处理原则是:当用户左右滑动时,需要让外部的view拦截点击事件,当用户上下滑动时,需要让内部的view拦截点击事件。场景2和场景3比较特殊,无法如同场景1一样原则的处理冲突,需要在业务上寻找突破点。比如业务上规定:当处于某种状态时需要外部View响应用户的滑动,而处于另一种状态时则需要内部View来响应View的滑动,根据这种业务上的需求我们也能得出相应的处理规则,有了处理规则同样可以进行下一步处理。
三、滑动冲突的解决方式
1.外部拦截法
外部拦截法是指点击事件都先经过父容器的拦截处理,如果父容器需要此事件就拦截 ,如果不需要此事件就不拦截。代码示例如下:
/** * 针对不同的滑动冲突,只需要修改父容器需要当前点击事件这个条件既可, * 其他均不需要做修改并且也不能修改 * @param event * @return */ 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;; } mLastXIntercepted = x; mLastYIntercepted = y; return intercepted; }
2.内部拦截法
内部拦截法是指父容器不拦截任何事件,所有的事件都传递给子元素,如果子元素需要此事件就直接消耗掉,否则就交由父容器进行处理,这种方法和Android中的事件分发机制不一致,需要配合requestDisallowInterceptTouchEvent方法才能正常工作,使用起来比外部拦截法稍显复杂。示例代码如下:
/** * 当面对不同的滑动策略时只需要修改里面的条件即可,其他不需要做改动 * 而且也不能有改动 * @param event * @return */ 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 deltaX = x - mLastX; int deltaY = y - mLastY; if(父容器需要此类点击事件){ parent.requestDisallowInterceptTouchEvent(false); } break; case MotionEvent.ACTION_UP: break;; } mLastX = x; mLastY = y; return super.dispatchTouchEvent(event); }