<?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>

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 布局文件如下:

下面看具体情况:

1. onInterceptTouchEvent() 处理 down 事件均返回 false onTouchEvent() 处理事件均返回 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 时, LayoutView1 LayoutView2 onTouchEvent 并不会收到事件 ,而是最终传递给了 MyTextView

2. LayoutView1 onInterceptTouchEvent() 处理 down 事件返回 true

MyTextView onTouchEvent() 处理事件返回 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. LayoutView1 LayoutView2 onInterceptTouchEvent() 处理 down 事件返回 false

MyTextView onTouchEvent() 处理事件返回 false

LayoutView2 onTouchEvent() 处理事件返回 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 注意,后续的 move up 事件均被传递给 LayoutView2 onTouchEvent() 处理,而没有传递给 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 ;    }} 

更多相关文章

  1. android 控件onClick事件的4种实现方式
  2. 关于Android 游戏开发中 OnTouchEvent() 触屏事件的性能优化笔记
  3. Android全屏模式,监听软键盘弹出事件。
  4. android 判断手机是否联网 的方法
  5. Android APP OPS移除应用程序项目的修改方法
  6. Android 开发 TextView中出现参差不齐状态解决方法
  7. reason: HttpHostConnect Connection to https://dl-ssl.google.

随机推荐

  1. android 根据TextView宽度 自动缩小字体
  2. android > APK更新
  3. Compile Busybox for Android
  4. android spinner 选中后显示字体的颜色设
  5. android window.requestWindowFeature()
  6. android webview 中网页数据与js交互
  7. java.lang.NullPointerException Attempt
  8. Android(安卓)Studio 用 JNI 实现与原生
  9. android蓝牙模块
  10. CheckBox android:paddingLeft 不兼容问