• Android中点击事件的处理解析及常见问题


          当我们手指按下时,Android采用层层传递-冒泡的方式处理点击事件。例如,现在公司来了个小项目,老板一看分配给经理做,经理一看分配给小组长,小组长一看好简单,分配给组员。如果在这个传递过程中(也就是还为分配到最底部时),某一层觉得我来负责这个比较好的话就会拦截掉这个消息,然后把它处理了,下面的就收不到有消息的这个通知。如果一直到了底层的话,组员如果能完成,就完成它。如果不能完成,那么就报告给组长,说组长我做不来,边学边做要影响进度。组长一看我也做不来,就给经理,经理一看我也不会,就给老板。这样也就一层层的传递了。 
          以上的意思也即:消息从上到下依次传递,如果在传递的过程中被拦截了就停止下传。如果没有被拦截,就一直传递到底部,如果底部不能够消耗该消息,那么就又一层层的返回来,返给上层,直到被消耗或者是到达最顶层。在此过程中,存在三个重要的方法:

        dispathTouchEvent(MotionEvent ev)  
    负责事件的分发,它的返回值就是表示是否消耗当前事件; onInterceptTouchEvent(MotionEvent ev)
    用于判断是否拦截该消息,如果当前View拦截了某个时间,那么在同一个事件序列中,此方法不会被再次调用。返回结果表示是否拦截当前事件 。 onTouchEvent(MotionEvent ev)
    处理事件。返回结果表示是否消耗当前事件,如果不消耗,则在同一时间序列中,当前View无法再次接收到事件。

          对于一个根ViewGroup来说,点击事件产生后,首先会传递给它,并调用它的dispath方法。如果这个ViewGroup的onIntercept方法返回true就表示它要拦截当前事件,false就表示不拦截,这个时候事件就会继续传递给子元素,接着调用子元素的dispath方法,一直重复以上过程到事件被处理。

          下面介绍一下常见的问题及解决方法:

    一、滑动冲突

         View的滑动冲突产生愿意大概可以分为三种:

    • 外部滑动和内部滑动方向不一致
    • 外部滑动方向和内部滑动方向一致
    • 嵌套上面两种情况

         比如说一个常见的,外部一个ListView,里面一个ScrollView,滑动时出现冲突?

    此时一般是采用外部拦截法(即结合onInterceptTouchEvent、onTouchEvent来进行解决。具体方法如下:

       (1)外部拦截法

          外部拦截法就是指所有的点击时间都经过父容器的拦截处理,如果父容器需要此事件就拦截,如果不需要此事件就不拦截。通过重写父容器的onInterceptTouchEvent方法:

     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;
     return intercepted;

    注:ACTION_DOWN事件父类容器就必须返回false,因为如果父类容器拦截了的话,后面的Move等所有事件都会直接由父类容器处理,就无法传给子元素了。UP事件也要返回false,因为它本身来说没有太多的意义,但是对于子元素就不同了,如果拦截了,那么子元素的onClick事件就无法触发。

    内部拦截法 
    这种方法指的是父容器不拦截任何时间,所有的事件都传递给子元素,如果子元素需要此事件就直接消耗掉,否则就交给父容器进行处理。它需要配合requestDisallowInterceptTouchEvent方法才能正常工作。我们需要重写子元素的dispatch方法。

        case MotionEvent.ACTION_DOWN:
        parent.requestDisallowInterceptTouchEvent(true);
        break;
        MotionEvent.ACTION_MOVE:
        if(父容器需要此类点击事件) {
        parent.requestDisallowInterceptTouchEvent(false);
        }
        break;
        return super.dispatchTouchEvent(event);

    这种方法的话父类容器需要默认拦截除了ACTION_DOWN以外的其他时间,这样当子元素调用request方法的时候父元素才能继续拦截所需的事件。

    其他的 
          如果觉得上面两个方式太复杂,看晕了,其实也可以自己根据项目的实际需要来指定自己的策略实现。例如根据你手指按的点的位置来判断你当前触碰的是哪个控件,以此来猜测用户是否是要对这个控件进行操作。如果点击的是空白的地方,就操作外部控件即可。

     ,具体可参考ViewPager中的滑动冲突

  • 相关阅读:
    黄聪:HBuilder左侧项目管理器如何不与标签页一起自动切换
    黄聪:is_file和file_exists效率比较
    黄聪:HBuilder复制PHP项目后,【转到定位】功能失效
    黄聪:jquery.bootgrid表格插件有的属性(visibleInSelection、cssClass、headerCssClass、headerAlign)不能识别的解决办法
    黄聪:PHP如何实现延迟一定时间后自动刷新当前页面、自动跳转header("refresh:1;url={$url}");
    黄聪:bootstrapValidator验证成功,按钮变灰却无法提交的问题
    黄聪:如何使用钩子定制WordPress添加媒体界面,去除不需要的元素
    黄聪:jquery+Datatables出现数据过长,表格不自动换行,columns设置width失效的办法
    黄聪:Jquery+DataTables插件,如何在ajax调用服务器数据后,自动给tr添加id属性
    黄聪:JQUERY判断操作CHECKBOX选中、取消选中、反选、第二次无法选中的问题
  • 原文地址:https://www.cnblogs.com/snow-flower/p/6111663.html
Copyright © 2020-2023  润新知