美文网首页Android开发app开发Android开发
你在Android中遇到过哪些滑动冲突?

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

作者: cooperise | 来源:发表于2016-08-20 17:56 被阅读505次

    对于滑动冲突,相信安卓开发的人都会有这种体会:本来从网上下载的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;
          }
    }
    

    相关文章

      网友评论

        本文标题:你在Android中遇到过哪些滑动冲突?

        本文链接:https://www.haomeiwen.com/subject/btsisttx.html