你在Android中遇到过哪些滑动冲突?

对于滑动冲突,相信安卓开发的人都会有这种体会:本来从网上下载的demo运行得好好的,但是只要出现滑动冲突,demo就无法正常工作了。许多开发者面对滑动冲突都会显得束手无策,(包括小编)于是小编就赶紧到处学习方法,并整理了下面的滑动冲突类型及解决方法,希望对和小编一样的初学者有帮助。

常见的冲突场景

  • 场景一:外部滑动方向和内部滑动方向不一致

外部滑动方向和内部滑动方向不一致

在主流应用中,几乎都会出现这种效果:首页可以通过左右滑动来切换页面,而每个页面内部往往又是一个ListView,这种情形下是有滑动冲突的(但是ViewPager内部处理了这种滑动冲突)

处理规则

—— 根据用户滑动的方向决定让内部View还是外部View拦截点击事件

  • 场景二:外部滑动方向和内部滑动方向一致

外部滑动方向和内部滑动方向一致

在这类场景里,可以想象父View可以通过上下滑动切换页面,然而内部还是一个ListView,当用户滑动的时候系统不知道该将滑动事件分发给谁

处理规则

—— 根据业务的规定决定让内部View还是外部View拦截点击事件

比如说上述例子,可以采用内部拦截法,优先将滑动事件交给内部ListView处理,当ListView已经到达顶部或者底部已经无法再进行同方向的滑动时,就将滑动事件交回给外部View处理,实现换页功能。

  • 场景三:上面两种情况的嵌套

多种情况的嵌套冲突

这类场景也很常见,假如你的首页是一个ViewPager,可以来回切换不同页面,每个页面中又有各自的ListView,然后其实还隐藏着一个SlidingMenu在左侧。

处理规则

—— 根据业务的规定决定让内部View还是外部View拦截点击事件

主要是最SlidingMenu的处理,业务上可以要求当用户的向右滑动是从app最左侧边缘开始时才将事件交给SlidingMenu处理。其他部分可以跟第一个场景一样。

常用解决方式

  • 外部拦截法 —— 点击事件都先经过父容器的拦截处理,如果父容器需要此事件就拦截,如果不需要此事件就不拦截。
    外部拦截需要重写父容器的onInterceptTouchEvent方法,伪代码如下:
    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:{
            // 对于ACTION_DOWN这个事件,父容器必须返回false,因为父容 器一旦拦截了
            // ACTION_DOWN,后续的ACTION_MOVE和ACTION_UP也都会直接交由父容器处理
            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;
    }
  • 内部拦截法 —— 指父容器不拦截任何事件,所有的事件都传递给子元素,如果子元素需要此事件就直接消耗掉,否则就交由父容器进行处理。
    内部拦截需要重写子元素的dispatchTouchEvent方法,伪代码如下:
    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 deltxY = y - mLastY;
            if (父容器需要当前点击事件) {
                 parent.requestDisallowInterceptTouchEvent(false);
            } 
            break;
       }
       case MotionEvent.ACTION_UP:{
            break;
       }
       default:
            break;
       }
       mLastX = x;
       mLastY = y;
       return super.dispatchTouchEvent(event);
    }
    另外,父容器也要做如下修改:
    public boolean onInterceptTouchEvent(MotionEvent event){
        int action = event.getAction();
        if (action == MotionEvent.ACTION_DOWN) {
            return false;
        } else {
            return true;
        }
    }
posted @ 2017-04-29 14:51  天涯海角路  阅读(192)  评论(0)    收藏  举报