android触屏事件处理onInterceptTouchEvent的问题

android官方文档有个标准解释,现摘录过来:
首先,看Android的官方文档正解

     
     
  1. onInterceptTouchEvent()与onTouchEvent()的机制: 
  2.   1. down事件首先会传递到onInterceptTouchEvent()方法 
  3.   2. 如果该ViewGrouponInterceptTouchEvent()在接收到down事件处理完成之return false,那么后续的move, up等事件将继续会先传递给该ViewGroup,之后才和down事件一样传递给最终的目标viewonTouchEvent()处理 
  4.   3. 如果该ViewGrouponInterceptTouchEvent()在接收到down事件处理完成之后return true,那么后续的move, up等事件将不再传递给onInterceptTouchEvent(),而是和down事件一样传递给该ViewGrouponTouchEvent()处理,注意,目标view将接收不到任何事件。 
  5.   4. 如果最终需要处理事件的viewonTouchEvent()返回了false,那么该事件将被传递至其上一层次的viewonTouchEvent()处理 
  6.   5. 如果最终需要处理事件的view onTouchEvent()返回了true,那么后续事件将可以继续传递给该viewonTouchEvent()处理。

仅仅看这个官方文档解释,就能理解清楚这两个函数关系以及用途的绝对是富有经验的framework高手。
否则,一定需要一个案例来阐释。假设我们有这样一个layout,非常典型的

     
     
  1. <com.test.LayoutView1 xmlns:android="http://schemas.android.com/apk/res/android"   
  2.     android:orientation="vertical" android:layout_width="fill_parent"   
  3.     android:layout_height="fill_parent">   
  4.     <com.test.LayoutView2   
  5.         android:orientation="vertical" android:layout_width="fill_parent"   
  6.         android:layout_height="fill_parent" android:gravity="center">   
  7.         <com.test.MyTextView   
  8.             android:layout_width="wrap_content"   android:layout_height="wrap_content"   
  9.       />   
  10.     </com.test.LayoutView2>   
  11. </com.test.LayoutView1>

用一个示例图来解释这个layout:

点击查看原始尺寸
通常外围的layoutview1,layoutview2,只是布局的容器不需要响应触屏的点击事件,仅仅Mytextview需要相应点击。但这只是一般情况,一些特殊的布局可能外围容器也要响应,甚至不让里面的mytextview去响应。更有特殊的情况是,动态更换响应对象。
那么首先看一下默认的触屏事件的在两个函数之间的传递流程。如下图:

点击查看原始尺寸

如果仅仅想让MyTextView来响应触屏事件,让MyTextView的OnTouchEvent返回true,那么事件流就变成如下图,可以看到layoutview1,layoutview2已经不能进入OnTouchEvent:

点击查看原始尺寸

另外一种情况,就是外围容器想独自处理触屏事件,那么就应该在相应的onInterceptTouchEvent函数中返回true,表示要截获触屏事件,比如layoutview1作截获处理,处理流变成如下图:

点击查看原始尺寸

以此类推,我们可以得到各种具体的情况,整个layout的view类层次中都有机会截获,而且能看出来外围的容器view具有优先截获权。

当我们去做一些相对来讲具有更复杂的触屏交互效果的应用时候,经常需要动态变更touch event的处理对象,比如launcher待机桌面和主菜单(见下图),从滑动屏幕开始到停止滑动过程当中,只有外围的容器view才可以处理touch event,否则就会误点击上面的应用图标或者widget.反之在静止不动的状态下则需要能够响应图标(子view)的touch事件。摘取framework中abslistview代码如下

     
     
  1. public boolean onInterceptTouchEvent(MotionEvent ev) { 
  2.         int action = ev.getAction(); 
  3.  
  4.         switch (action & MotionEvent.ACTION_MASK) { 
  5.         case MotionEvent.ACTION_DOWN: { 
  6.   
  7.             if (touchMode == TOUCH_MODE_FLING) { 
  8.                 return true;  //fling状态,截获touch,因为在滑动状态,不让子view处理 
  9.             } 
  10.             break; 
  11.         } 
  12.  
  13.         case MotionEvent.ACTION_MOVE: { 
  14.             switch (mTouchMode) { 
  15.             case TOUCH_MODE_DOWN: 
  16.                 final int pointerIndex = ev.findPointerIndex(mActivePointerId); 
  17.                 final int y = (int) ev.getY(pointerIndex); 
  18.                 if (startScrollIfNeeded(y - mMotionY)) { 
  19.                     return true;//开始滑动状态,截获touch事件,不让子view处理 
  20.                 } 
  21.                 break; 
  22.             } 
  23.             break; 
  24.         } 
  25. }

请输入图片描述

请输入图片描述

总结:

仅仅通过概览性的官方文档是很难理解onInterceptTouchEvent函数的用途的,只有通过演绎这个抽象的规则,配以图文才能获取这个重要的知识。很显然,默认是返回false,不做截获。返回true之后,事件流的后端控件就没有机会处理touch事件了,把默认的事件流中每个处理函数看作一个节点,这个节点只要返回true, 后续的事件就被截止了,这样想就很好理解。

 

 

onInterceptTouchEvent是在ViewGroup里面定义的。Android中的layout布局类一般都是继承此类的。onInterceptTouchEvent是用于拦截手势事件的,每个手势事件都会先调用onInterceptTouchEvent。
onInterceptTouchEvent()用于处理事件并改变事件的传递方向。返回值为false时事件会传递给子控件的onInterceptTouchEvent();返回值为true时事件会传递给当前控件的onTouchEvent(),而不在传递给子控件,这就是所谓的Intercept(截断)。
onTouchEvent() 用于处理事件,返回值决定当前控件是否消费(consume)了这个事件。可能你要问是否消费了又区别吗,反正我已经针对事件编写了处理代码?答案是有区别!比如ACTION_MOVE或者ACTION_UP发生的前提是一定曾经发生了ACTION_DOWN,如果你没有消费ACTION_DOWN,那么系统会认为ACTION_DOWN没有发生过,所以ACTION_MOVE或者ACTION_UP就不能被捕获。

转自:http://www.dewen.org/q/2438

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值