onInterceptTouchEvent和onTouchEvent调用时序

onInterceptTouchEvent()是ViewGroup的一个方法,目的是在系统向该ViewGroup及其各个childView触发onTouchEvent()之前对相关事件进行一次拦截,Android这么设计的想法也很好理解,由于ViewGroup会包含若干childView,因此需要能够统一监控各种touch事件的机会,因此纯粹的不能包含子view的控件是没有这个方法的,如LinearLayout就有,TextView就没有。

onInterceptTouchEvent()使用也很简单,如果在ViewGroup里覆写了该方法,那么就可以对各种touch事件加以拦截。但是如何拦截,是否所有的touch事件都需要拦截则是比较复杂的,touch事件在onInterceptTouchEvent()和onTouchEvent以及各个childView间的传递机制完全取决于onInterceptTouchEvent()和onTouchEvent()的返回值。并且,针对down事件处理的返回值直接影响到后续move和up事件的接收和传递。

关于返回值的问题,基本规则很清楚,如果return true,那么表示该方法消费了此次事件,如果return false,那么表示该方法并未处理完全,该事件仍然需要以某种方式传递下去继续等待处理。

SDK给出的说明如下:

  • You will receive the down event here.
  • The down event will be handled either by a child of this view group, or given to your own onTouchEvent() method to handle; this means you should implement onTouchEvent() to return true, so you will continue to see the rest of the gesture (instead of looking for a parent view to handle it). Also, by returning true from onTouchEvent(), you will not receive any following events in onInterceptTouchEvent() and all touch processing must happen in onTouchEvent() like normal.
  • For as long as you return false from this function, each following event (up to and including the final up) will be delivered first here and then to the target's onTouchEvent().
  • If you return true from here, you will not receive any following events: the target view will receive the same event but with the action ACTION_CANCEL, and all further events will be delivered to your onTouchEvent() method and no longer appear here.

由于onInterceptTouchEvent()的机制比较复杂,上面的说明写的也比较复杂,总结一下,基本的规则是:

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

下面用一个简单的实验说明上述复杂的规则。视图自底向上共3层,其中LayoutView1和LayoutView2就是LinearLayout,MyTextView就是TextView:

对应的xml布局文件如下:

<?xml version="1.0" encoding="utf-8"?>
<com.touchstudy.LayoutView1 xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<com.touchstudy.LayoutView2
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center">
<com.touchstudy.MyTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/tv"
android:text="AB"
android:textSize="40sp"
android:textStyle="bold"
android:background="#FFFFFF"
android:textColor="#0000FF"/>
</com.touchstudy.LayoutView2>
</com.touchstudy.LayoutView1>

下面看具体情况:

      1.onInterceptTouchEvent()处理down事件均返回falseonTouchEvent()处理事件均返回true

------------------------------------------------------------------------------------------------------------------------------
04-11 03:58:42.620: DEBUG/LayoutView1(614): onInterceptTouchEvent action:ACTION_DOWN
04-11 03:58:42.620: DEBUG/LayoutView2(614): onInterceptTouchEvent action:ACTION_DOWN
04-11 03:58:42.620: DEBUG/MyTextView(614): onTouchEvent action:ACTION_DOWN
04-11 03:58:42.800: DEBUG/LayoutView1(614): onInterceptTouchEvent action:ACTION_MOVE
04-11 03:58:42.800: DEBUG/LayoutView2(614): onInterceptTouchEvent action:ACTION_MOVE
04-11 03:58:42.800: DEBUG/MyTextView(614): onTouchEvent action:ACTION_MOVE
…… //省略过多的ACTION_MOVE
04-11 03:58:43.130: DEBUG/LayoutView1(614): onInterceptTouchEvent action:ACTION_UP
04-11 03:58:43.130: DEBUG/LayoutView2(614): onInterceptTouchEvent action:ACTION_UP
04-11 03:58:43.150: DEBUG/MyTextView(614): onTouchEvent action:ACTION_UP
------------------------------------------------------------------------------------------------------------------------------

  总结:这是最常见的情况,onInterceptTouchEvent并没有做任何改变事件传递时序的操作,效果上和没有覆写该方法是一样的。可以看到,各种事件的传递本身是自底向上的,次序是:LayoutView1->LayoutView2->MyTextView。注意,在onInterceptTouchEvent均返回false时,LayoutView1LayoutView2onTouchEvent并不会收到事件,而是最终传递给了MyTextView。

  2.LayoutView1onInterceptTouchEvent()处理down事件返回trueMyTextViewonTouchEvent()处理事件返回true

------------------------------------------------------------------------------------------------------------------------------
04-11 03:09:27.589: DEBUG/LayoutView1(446): onInterceptTouchEvent action:ACTION_DOWN
04-11 03:09:27.589: DEBUG/LayoutView1(446): onTouchEvent action:ACTION_DOWN
04-11 03:09:27.629: DEBUG/LayoutView1(446): onTouchEvent action:ACTION_MOVE
04-11 03:09:27.689: DEBUG/LayoutView1(446): onTouchEvent action:ACTION_MOVE
…… //省略过多的ACTION_MOVE
04-11 03:09:27.959: DEBUG/LayoutView1(446): onTouchEvent action:ACTION_UP
------------------------------------------------------------------------------------------------------------------------------

  总结: 从Log可以看到,由于LayoutView1在拦截第一次down事件时return true,所以后续的事件(包括第一次的down)将由LayoutView1本身处理,事件不再传递下去。

  

  3.LayoutView1LayoutView2onInterceptTouchEvent()处理down事件返回falseMyTextViewonTouchEvent()处理事件返回false,LayoutView2onTouchEvent()处理事件返回true

----------------------------------------------------------------------------------------------------------------------------
04-11 09:50:21.147: DEBUG/LayoutView1(301): onInterceptTouchEvent action:ACTION_DOWN
04-11 09:50:21.147: DEBUG/LayoutView2(301): onInterceptTouchEvent action:ACTION_DOWN
04-11 09:50:21.147: DEBUG/MyTextView(301): onTouchEvent action:ACTION_DOWN
04-11 09:50:21.147: DEBUG/LayoutView2(301): onTouchEvent action:ACTION_DOWN
04-11 09:50:21.176: DEBUG/LayoutView1(301): onInterceptTouchEvent action:ACTION_MOVE
04-11 09:50:21.176: DEBUG/LayoutView2(301): onTouchEvent action:ACTION_MOVE
04-11 09:50:21.206: DEBUG/LayoutView1(301): onInterceptTouchEvent action:ACTION_MOVE
04-11 09:50:21.217: DEBUG/LayoutView2(301): onTouchEvent action:ACTION_MOVE
…… //省略过多的ACTION_MOVE
04-11 09:50:21.486: DEBUG/LayoutView1(301): onInterceptTouchEvent action:ACTION_UP
04-11 09:50:21.486: DEBUG/LayoutView2(301): onTouchEvent action:ACTION_UP
----------------------------------------------------------------------------------------------------------------------------

  总结: 可以看到,由于MyTextView在onTouchEvent()中return false,down事件被传递给其父view,即LayoutView2的onTouchEvent()方法处理,由于在LayoutView2的onTouchEvent()中return true,所以down事件传递并没有上传到LayoutView1。注意,后续的moveup事件均被传递给LayoutView2onTouchEvent()处理,而没有传递给MyTextView

  应大家的要求,我把源代码贴上,其实很简单,就是基础文件,主要是用来观察事件的传递。

  主Activity: InterceptTouchStudyActivity.Java

public class InterceptTouchStudyActivity extends Activity {

    static final String TAG = "ITSActivity";

    TextView tv;

    /** Called when the activity is first created. */

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.layers_touch_pass_test);

     }

 }

LayoutView1.java:

public class LayoutView1 extends LinearLayout {

         private final String TAG = "LayoutView1";

           public LayoutView1(Context context, AttributeSet attrs) {

         super(context, attrs);

         Log.d(TAG,TAG);

     }

     @Override
public boolean onInterceptTouchEvent(MotionEvent ev) { int action = ev.getAction(); switch(action){ case MotionEvent.ACTION_DOWN: Log.d(TAG,"onInterceptTouchEvent action:ACTION_DOWN"); // return true; break; case MotionEvent.ACTION_MOVE: Log.d(TAG,"onInterceptTouchEvent action:ACTION_MOVE"); break; case MotionEvent.ACTION_UP: Log.d(TAG,"onInterceptTouchEvent action:ACTION_UP"); break; case MotionEvent.ACTION_CANCEL: Log.d(TAG,"onInterceptTouchEvent action:ACTION_CANCEL"); break; }
return false; }
@Override
public boolean onTouchEvent(MotionEvent ev) { int action = ev.getAction(); switch(action){ case MotionEvent.ACTION_DOWN: Log.d(TAG,"onTouchEvent action:ACTION_DOWN"); break; case MotionEvent.ACTION_MOVE: Log.d(TAG,"onTouchEvent action:ACTION_MOVE"); break; case MotionEvent.ACTION_UP: Log.d(TAG,"onTouchEvent action:ACTION_UP"); break; case MotionEvent.ACTION_CANCEL: Log.d(TAG,"onTouchEvent action:ACTION_CANCEL"); break; }
return true;
} @Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// TODO Auto-generated method stub
super.onLayout(changed, l, t, r, b);
} @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
} }

LayoutView2.java:

public class LayoutView2 extends LinearLayout {

    private final String TAG = "LayoutView2";

    public LayoutView2(Context context, AttributeSet attrs) {

       super(context, attrs);

       Log.d(TAG,TAG);

    }

    @Override
public boolean onInterceptTouchEvent(MotionEvent ev) { int action = ev.getAction(); switch(action){ case MotionEvent.ACTION_DOWN: Log.d(TAG,"onInterceptTouchEvent action:ACTION_DOWN"); break; case MotionEvent.ACTION_MOVE: Log.d(TAG,"onInterceptTouchEvent action:ACTION_MOVE"); break; case MotionEvent.ACTION_UP: Log.d(TAG,"onInterceptTouchEvent action:ACTION_UP"); break; case MotionEvent.ACTION_CANCEL: Log.d(TAG,"onInterceptTouchEvent action:ACTION_CANCEL"); break;
}
return false;
} @Override public boolean onTouchEvent(MotionEvent ev) { int action = ev.getAction(); switch(action){
case MotionEvent.ACTION_DOWN:
Log.d(TAG,"onTouchEvent action:ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.d(TAG,"onTouchEvent action:ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.d(TAG,"onTouchEvent action:ACTION_UP");
break;
case MotionEvent.ACTION_CANCEL:
Log.d(TAG,"onTouchEvent action:ACTION_CANCEL");
break;
}
return true; } }

MyTextView.java:

public class MyTextView extends TextView {

    private final String TAG = "MyTextView";
public MyTextView(Context context, AttributeSet attrs) { super(context, attrs);
Log.d(TAG,TAG);
} @Override
public boolean onTouchEvent(MotionEvent ev) { int action = ev.getAction(); switch(action){ case MotionEvent.ACTION_DOWN: Log.d(TAG,"onTouchEvent action:ACTION_DOWN"); break; case MotionEvent.ACTION_MOVE: Log.d(TAG,"onTouchEvent action:ACTION_MOVE"); break; case MotionEvent.ACTION_UP: Log.d(TAG,"onTouchEvent action:ACTION_UP"); break; case MotionEvent.ACTION_CANCEL: Log.d(TAG,"onTouchEvent action:ACTION_CANCEL"); break;
}
return false;
}
public void onClick(View v) { Log.d(TAG, "onClick"); } public boolean onLongClick(View v) { Log.d(TAG, "onLongClick"); return false;
}
}

转自:http://blog.csdn.net/ddna/article/details/5473293

下一篇推荐 :Android onTouchEvent, onClick及onLongClick的调用机制

onInterceptTouchEvent和onTouchEvent调用时序(转)的更多相关文章

  1. onInterceptTouchEvent和onTouchEvent调用时序

    onInterceptTouchEvent()是ViewGroup的一个方法,目的是在系统向该ViewGroup及其各个childView触发onTouchEvent()之前对相关事件进行一次拦截,A ...

  2. onInterceptTouchEvent和onTouchEvent调用关系详解 ...

    http://blog.csdn.net/lvxiangan/article/details/9309927 老实说,这两个小东东实在是太麻烦了,很不好懂,我自己那api文档都头晕,在网上找到很多资料 ...

  3. Android Touch系统简介(二):实例详解onInterceptTouchEvent与onTouchEvent的调用过程

    上一篇文章主要讲述了Android的TouchEvent的分发过程,其中有两个重要的函数:onInterceptTouchEvent和onTouchEvent,这两个函数可被重装以完成特定的逻辑.on ...

  4. Android Touch系统简介(二):实例详解onInterceptTouchEvent与onTouchEvent的调用过程

    上一篇文章主要讲述了Android的TouchEvent的分发过程,其中有两个重要的函数:onInterceptTouchEvent和onTouchEvent,这两个函数可被重装以完成特定的逻辑.on ...

  5. Android学习笔记之dispatchTouchEvent和OnInterceptTouchEvent和OnTouchEvent三个方法之间的联系...

    PS:好久没有写博客了,项目正式开始启动了,但是怎么也打不起精神来...可能还是不适应放假留校...这下一年只能回家一次了...伤感...写篇博客舒坦下... 学习内容:   Android中disp ...

  6. Android在onInterceptTouchEvent与onTouchEvent

    onInterceptTouchEvent: onInterceptTouchEvent是在ViewGroup里面定义的.Android中的layout布局类一般都是继承此类的.onIntercept ...

  7. onInterceptTouchEvent 与 onTouchEvent 分析与MotionEvent在ViewGroup与View中的分发

    onInterceptTouchEvent 与 onTouchEvent 分析与MotionEvent在ViewGroup与View中的分发        Notice:本文将紧接着 Android ...

  8. 事件分发时候的onTouchEvent,onInterceptTouchEvent,dispatchTouchEvent调用顺序

    一直想弄清楚onTouchEvent,onInterceptTouchEvent,dispatchTouchEvent的执行顺序,以及内部使用switch (event.getAction())中的执 ...

  9. Android中的dispatchTouchEvent()、onInterceptTouchEvent()和onTouchEvent()

     dispatchTouchEvent (分发TouchEvent) 处理触摸事件分发,事件(多数情况)是从Activity的dispatchTouchEvent开始的.执行super.dispatc ...

随机推荐

  1. noip2017集训测试赛(十一)Problem C: 循环移位

    题面 Description 给定一个字符串 ss .现在问你有多少个本质不同的 ss 的子串 t=t1t2⋯tm(m>0)t=t1t2⋯tm(m>0) 使得将 tt 循环左移一位后变成的 ...

  2. 解魔方的机器人攻略14 – 安装Lejos(下)

    由 动力老男孩 发表于 2009/12/27 17:16:11 第四步:安装Lejos 登陆 Lejos 主页点击 NXT 图片进入 Lejos 下载页面,点击 NXJ 的下载链接: 下载完成后将下载 ...

  3. Android Developer -- Bluetooth篇 开发实例之四 API详解

    http://www.open-open.com/lib/view/open1390879771695.html 这篇文章将会详细解析BluetoothAdapter的详细api, 包括隐藏方法, 每 ...

  4. numpy自动生成数组

    1 np.arange(),类似于range,通过指定开始值,终值和步长来创建表示等差数列的一维数组,注意该函数和range一样结果不包含终值. >>> np.arange(10) ...

  5. C语言中不同类型的数据转换规则

    不同类型数据间的混合运算与类型转换 1.自动类型转换 在C语言中,自动类型转换遵循以下规则: ①若参与运算量的类型不同,则先转换成同一类型,然后进行运算 ②转换按数据长度增加的方向进行,以保证精度不降 ...

  6. Java高级特性—反射和动态代理

    1).反射 通过反射的方式可以获取class对象中的属性.方法.构造函数等,一下是实例: 2).动态代理 使用场景: 在之前的代码调用阶段,我们用action调用service的方法实现业务即可. 由 ...

  7. 栅格 CSS中的循环 媒体查询

    第三天Bootstrap 模态框 1.要使用模态框,需要现在body里,添加展示模态框的html代码.此时模态框是看不见的 2.如果要显示,$(“.modal”).modal(“show”); 3.如 ...

  8. [GraphQL] Reuse Query Fields with GraphQL Fragments

    A GraphQL fragment encapsulates a collection of fields that can be included in queries. In this vide ...

  9. Spring3的quartz定时任务

    要使用定时任务,需要将quartz-1.5.2.jar加入lib,没有的话可以从下面地址下载: quartz-1.5.2.jar 有了这个再做个配置文件appctx-quartz.xml: <? ...

  10. 点击Div,显示其innerHTML

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...