Android中的事件模型

来源:互联网 发布:早教机软件什么格式 编辑:程序博客网 时间:2024/04/27 13:43


以前写 android ,对事件的处理没有太深入,只是简单的 onTouchEvent  ok 了,现在写的 UI ,很多自定义组件,父 view 和子view 都需要接收事件,然后处理。如果不弄明白它的事件传递机制,很难拥有好的用户体验。

Touchevent 中,返回值是 true ,则说明消耗掉了这个事件,返回值是 false ,则没有消耗掉,会继续传递下去,这个是最基本的。

 View 中跟 Touch 相关的事件有 dispatchTouchEvent  interceptTouchEvnet  onTouchEvent 三种。 dispatchTouchEvent是负责分发事件的,事件从 activity 传递出来之后,最先到达的就是最顶层 view  dispatchTouchEvent ,然后它进行分发,如果返回false ,则交给这个 view  interceptTouchEvent 方法来决定是否要拦截这个事件,如果 interceptTouchEvent 返回 true ,也就是拦截掉了,则交给它的 onTouchEvent 来处理,如果 interceptTouchEvent 返回 false ,那么就传递给子 view ,由子 view dispatchTouchEvent 再来开始这个事件的分发。

如果事件传递到某一层的子 view  onTouchEvent 上了,这个方法返回了 false ,那么这个事件会从这个 view 往上传递,都是onTouchEvent 来接收。而如果传递到最上面的 onTouchEvent 也返回 false 的话,这个事件就会“消失”,而且接收不到下一次事件。(我说的一次事件指的是 down  up 之间的一系列事件)

我画了个图,见附件。

总结一下,如果这一次事件没有人消耗掉,则系统不会给你下一次事件,因为他会认为你这次的事件阻塞了,没必要给下一次。onTouchEvent如果不消耗的话,会从子view传递到父view。

 

 

又一个例子:

 

需求:要做一个完全通过flip手势来切换的界面。在最上层用一个ViewFlipper作为容器,并检测flip手势操作。

难题:ViewFlipper的flip手势检测需要的MotionEvent会被各种子View的触摸检测给拦截了。比如界面上有一个Button,则当手指按下Button(还没有抬起)然后flip出Button,则最上层的flip手势检测无效。

原因:android对Touch Event的分发逻辑是View从上层分发到下层(dispatchTouchEvent函数),然后下层优先开始处理Event(先mOnTouchListener,再onTouchEvent)并向上返回处理情况(boolean值),若返回true,则上层不再处理。

    于是我们首先想到,要保证flip手势检测,需要把所有的Touch Event都传到上层去。

    然而在分发逻辑之外还有一个逻辑,android估计是为了保证每个触操作只能由一个View来进行完整响应,对ACTION_DOWN事件有个额外的逻辑:如果某个View在处理ACTION_DOWN事件时返回false(即该View未处理此事件),那么后续产生的其它事件将直接忽略掉这个View(不过LongPress又有另外的独立逻辑)。举例来说就是,如果你处理ACTION_DOWN时返回了false,那么你这个View将得不到ACTION_MOVE或ACTION_DOWN等等这些后续事件了。

     于是难题出现了,你若把Touch Event都想办法给传到上层了(只能通过返回false来传到上层),那么下层的各种子View就不能处理后续事件了。

解决方案:

     开始仅着眼于Touch Event处理完后的回传过程,想了N久不得,毕竟我想实现的是一个需要打破android事件处理逻辑的效果(就是一个连续性操作,只有不满足上层要求时,才轮到下层处理)。然后突然想到事件的分发过程,便豁然开朗:

     覆写最上层的View的dispatchTouchEvent函数,代码如下:

      @Override
      public boolean dispatchTouchEvent(MotionEvent event) {

             if (_flipDetector.onTouchEvent(event)) {
             event.setAction(MotionEvent.ACTION_CANCEL);
             }

             return super.dispatchTouchEvent(event);
      }

      于是效果实现。也就是在分发之前便进行手势检测处理,若检测成功,则取消下层的一切处理过程。

0 0
原创粉丝点击