zoukankan      html  css  js  c++  java
  • Android事件模型之interceptTouchEvnet ,onTouchEvent关系正解

    首先,看Android的官方文档正解

     

    onInterceptTouchEvent()与onTouchEvent()的机制:

      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()处理

    这是官方文档的说法,要是自己没亲自去写个程序观察哈,基本上没法理解,所以上程序先,然后分析:

     

     

    布局文件main.xml

     

    Java代码  收藏代码
    1. <span style="font-size: small;"><?xml version="1.0" encoding="utf-8"?>  
    2. <com.hao.LayoutView1 xmlns:android="http://schemas.android.com/apk/res/android"  
    3.     android:orientation="vertical" android:layout_width="fill_parent"  
    4.     android:layout_height="fill_parent">  
    5.     <com.hao.LayoutView2  
    6.         android:orientation="vertical" android:layout_width="fill_parent"  
    7.         android:layout_height="fill_parent" android:gravity="center">  
    8.         <com.hao.MyTextView  
    9.             android:layout_width="wrap_content" android:layout_height="wrap_content"  
    10.             android:id="@+id/tv" android:text="AB" android:textSize="40sp"  
    11.             android:textStyle="bold" android:background="#FFFFFF"  
    12.             android:textColor="#0000FF" />  
    13.     </com.hao.LayoutView2>  
    14. </com.hao.LayoutView1>   
    15. </span>  

     第一层自定义布局LayoutView1.java

     

    Java代码  收藏代码
    1. <span style="font-size: small;">package com.hao;  
    2.   
    3. import android.content.Context;  
    4. import android.util.AttributeSet;  
    5. import android.util.Log;  
    6. import android.view.MotionEvent;  
    7. import android.widget.LinearLayout;  
    8.   
    9. public class LayoutView1 extends LinearLayout {  
    10.      private final String TAG = "LayoutView1";   
    11.      public LayoutView1(Context context, AttributeSet attrs) {   
    12.          super(context, attrs);   
    13.          Log.e(TAG,TAG);   
    14.      }  
    15.        
    16.      @Override   
    17.      public boolean onInterceptTouchEvent(MotionEvent ev) {   
    18.          int action = ev.getAction();   
    19.          switch(action){   
    20.          case MotionEvent.ACTION_DOWN:   
    21.               Log.e(TAG,"onInterceptTouchEvent action:ACTION_DOWN");   
    22. //              return true; 在这就拦截了,后面的就不会得到事件  
    23.               break;  
    24.         case MotionEvent.ACTION_MOVE:   
    25.               Log.e(TAG,"onInterceptTouchEvent action:ACTION_MOVE");   
    26.               break;   
    27.          case MotionEvent.ACTION_UP:   
    28.               Log.e(TAG,"onInterceptTouchEvent action:ACTION_UP");   
    29.               break;   
    30.          case MotionEvent.ACTION_CANCEL:   
    31.               Log.e(TAG,"onInterceptTouchEvent action:ACTION_CANCEL");   
    32.               break;   
    33.          }   
    34.          return false;   
    35.      }   
    36.   
    37.      @Override   
    38.      public boolean onTouchEvent(MotionEvent ev) {   
    39.          int action = ev.getAction();   
    40.          switch(action){   
    41.          case MotionEvent.ACTION_DOWN:   
    42.               Log.e(TAG,"onTouchEvent action:ACTION_DOWN");   
    43.               break;   
    44.          case MotionEvent.ACTION_MOVE:   
    45.               Log.e(TAG,"onTouchEvent action:ACTION_MOVE");   
    46.               break;   
    47.          case MotionEvent.ACTION_UP:   
    48.               Log.e(TAG,"onTouchEvent action:ACTION_UP");   
    49.               break;   
    50.          case MotionEvent.ACTION_CANCEL:   
    51.               Log.e(TAG,"onTouchEvent action:ACTION_CANCEL");   
    52.               break;   
    53.          }   
    54.          return true;   
    55. //         return false;  
    56.      }   
    57.        
    58.      @Override   
    59.      protected void onLayout(boolean changed, int l, int t, int r, int b) {   
    60.          // TODO Auto-generated method stub   
    61.          super.onLayout(changed, l, t, r, b);   
    62.      }   
    63.   
    64.      @Override   
    65.      protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {   
    66.          // TODO Auto-generated method stub   
    67.          super.onMeasure(widthMeasureSpec, heightMeasureSpec);   
    68.      }   
    69. }</span>  

     第二层布局LayoutView2.java

     

    Java代码  收藏代码
    1. <span style="font-size: small;">package com.hao;  
    2.   
    3. import android.content.Context;  
    4. import android.util.AttributeSet;  
    5. import android.util.Log;  
    6. import android.view.MotionEvent;  
    7. import android.widget.LinearLayout;  
    8.   
    9. public class LayoutView2 extends LinearLayout {  
    10.       
    11.     private final String TAG = "LayoutView2";   
    12.     public LayoutView2(Context context, AttributeSet attrs) {   
    13.        super(context, attrs);   
    14.        Log.e(TAG,TAG);   
    15.     }   
    16.       
    17.     @Override   
    18.     public boolean onInterceptTouchEvent(MotionEvent ev) {   
    19.        int action = ev.getAction();   
    20.        switch(action){   
    21.        case MotionEvent.ACTION_DOWN:   
    22.            Log.e(TAG,"onInterceptTouchEvent action:ACTION_DOWN");  
    23. //           return true;  
    24.            break;   
    25.        case MotionEvent.ACTION_MOVE:   
    26.            Log.e(TAG,"onInterceptTouchEvent action:ACTION_MOVE");   
    27.            break;   
    28.        case MotionEvent.ACTION_UP:   
    29.            Log.e(TAG,"onInterceptTouchEvent action:ACTION_UP");   
    30.            break;   
    31.        case MotionEvent.ACTION_CANCEL:   
    32.            Log.e(TAG,"onInterceptTouchEvent action:ACTION_CANCEL");   
    33.            break;   
    34.        }   
    35.        return false;   
    36.     }   
    37.   
    38.     @Override   
    39.     public boolean onTouchEvent(MotionEvent ev) {   
    40.        int action = ev.getAction();   
    41.        switch(action){   
    42.        case MotionEvent.ACTION_DOWN:   
    43.            Log.e(TAG,"onTouchEvent action:ACTION_DOWN");   
    44.            break;   
    45.        case MotionEvent.ACTION_MOVE:   
    46.            Log.e(TAG,"onTouchEvent action:ACTION_MOVE");   
    47.            break;   
    48.        case MotionEvent.ACTION_UP:   
    49.            Log.e(TAG,"onTouchEvent action:ACTION_UP");   
    50.            break;   
    51.        case MotionEvent.ACTION_CANCEL:   
    52.            Log.e(TAG,"onTouchEvent action:ACTION_CANCEL");   
    53.            break;   
    54.        }   
    55. //       return true;   
    56.        return false;  
    57.     }   
    58. }  
    59. </span>  

     自定义MyTextView.java

     

    Java代码  收藏代码
    1. <span style="font-size: small;">package com.hao;  
    2.   
    3. import android.content.Context;  
    4. import android.util.AttributeSet;  
    5. import android.util.Log;  
    6. import android.view.MotionEvent;  
    7. import android.view.View;  
    8. import android.widget.TextView;  
    9.   
    10. public class MyTextView extends TextView {  
    11.     private final String TAG = "MyTextView";   
    12.     public MyTextView(Context context, AttributeSet attrs) {   
    13.        super(context, attrs);   
    14.        Log.e(TAG,TAG);   
    15.     }   
    16.   
    17.     @Override   
    18.     public boolean onTouchEvent(MotionEvent ev) {   
    19.        int action = ev.getAction();   
    20.        switch(action){   
    21.        case MotionEvent.ACTION_DOWN:   
    22.            Log.e(TAG,"onTouchEvent action:ACTION_DOWN");   
    23.            break;   
    24.        case MotionEvent.ACTION_MOVE:   
    25.            Log.e(TAG,"onTouchEvent action:ACTION_MOVE");   
    26.            break;   
    27.        case MotionEvent.ACTION_UP:   
    28.            Log.e(TAG,"onTouchEvent action:ACTION_UP");   
    29.            break;   
    30.        case MotionEvent.ACTION_CANCEL:   
    31.            Log.e(TAG,"onTouchEvent action:ACTION_CANCEL");   
    32.            break;   
    33.        }   
    34.        return false;   
    35. //       return true;  
    36.     }   
    37.   
    38.     public void onClick(View v) {   
    39.        Log.e(TAG, "onClick");   
    40.     }   
    41.   
    42.     public boolean onLongClick(View v) {   
    43.        Log.e(TAG, "onLongClick");   
    44.        return false;   
    45.     }   
    46. }  
    47. </span>  

     其实代码很简单,就是自定义了View,在View里面都重写了interceptTouchEvnet (),和onTouchEvent(),然后测试其返回值,对监听的影响,关键是自己动手,逐个测试,并预测结果,等你能预测结果的时候,也就懂了,需要修改的地方就是interceptTouchEvnet 和onTouchEvent的返回值,他们决定了事件监听的流程,下面我画了一张图,如有不足之处欢迎指正,谢谢!

     

    下面是我的正解:

    基本的规则是: 
          *1.down事件首先会传递到onInterceptTouchEvent()方法 
          * 
          * 2.如果该ViewGroup的onInterceptTouchEvent()在接收到down事件处理完成之后return false(不拦截),
          * 那么后续的move, up等事件将继续会先传递给该ViewGroup,之后才和down事件一样传递给最终的目标view的onTouchEvent()处理。 
          *
          * 3.如果该ViewGroup的onInterceptTouchEvent()在接收到down事件处理完成之后return true(拦截,那么后面的move,up事件不需要在看因为已经拦截了, 我们直接拿去处理onTouchEvent()就可以了),那么后续的move, up等事件将不再传递给onInterceptTouchEvent(), 而是和down事件一样传递给该ViewGroup的onTouchEvent()处理,注意,目标view将接收不到任何事件。 下面例子演示:
          * 1:LayoutView1(31375): onInterceptTouchEvent action:ACTION_DOWN
          * 2:LayoutView2(31375): onInterceptTouchEvent action:ACTION_DOWN
          * 3:LayoutView2(31375): onTouchEvent action:ACTION_DOWN
          * 4:LayoutView1(31375): onInterceptTouchEvent action:ACTION_MOVE
          * 5:LayoutView2(31375): onTouchEvent action:ACTION_MOVE
          * 6:LayoutView1(31375): onInterceptTouchEvent action:ACTION_MOVE
          * 7:LayoutView2(31375): onTouchEvent action:ACTION_MOVE
          * 8:LayoutView1(31375): onInterceptTouchEvent action:ACTION_UP
          * 9:LayoutView2(31375): onTouchEvent action:ACTION_UP
          * 该设置为:
          * onInterceptTouchEvent:LayoutView1为false,LayoutView2为true
          * onTouchEvent:LayoutView2为true
          * 故而事件在LayoutView2(onInterceptTouchEvent:返回true)时被拦截并处理,根据上面说法就是LayoutView2后续的MOVE,UP操作都不在经过onInterceptTouchEvent,直接
          * 交给onTouchEvent处理,结果也的确如此。(见:LayoutView2的3,5,7,9,第一次是onInterceptTouchEvent处理如1,以后交给onTouchEvent)
          * 而LayoutView1都还是要经过onInterceptTouchEvent(见LayoutView1的4,6,8)
          * 
          * 4.如果最终需要处理事件的view的onTouchEvent()返回了false(没能处理这个事件,不能丢在传回来让父继续),
          * 那么该事件将被传递至其上一层次的view的onTouchEvent()处理。 
          * **************************************************************************
          * 感觉像是一个圈,然后一直在找一个能处理这个消息的人,如果找到了就结束,没找到就循环,直到回到发出消息的那个人
          * 注(对下面):没有标注的DOWN表示拦截事件onInterceptTouchEvent,标注了onTouchEvent就是处理事件
          * a.如果都没处理(onInterceptTouchEvent返回false):
    A(DOWN)-->B(DOWN)-->C(onTouchEvent DOWN)-->B(onTouchEvent DOWN)-->A(onTouchEvent DOWN),没有执行UP事件,注意有MOVE的话,在DOWN和UP之间,下面的都一样。
          *b. B处理(B的onInterceptTouchEvent返回true):
    A(DOWN)-->B(DOWN)-->B(onTouchEvent)-->A(onTouchEvent UP)-->B(onTouchEvent UP)-->(over)
          *
    形象说明:如果父亲不拦截消息就传给儿子,如果儿子要这个消息就处理(DOWN),结束,然后有父亲1--父亲2--儿子以此释放消息(UP)。 然是如果儿子对这个消息置之不理,那这个消息又传回父亲,由父亲来处理即。
     
    下面给出了5中情况(不拦截表示onInterceptTouchEvent返回false):
          * 11** 父亲1(LayoutView1不拦截false)---父亲2(LayoutView2不拦截false)--儿子(MyTextView,onTouchEvent return true)--结束
          * 22** 父亲1(LayoutView1不拦截false)---父亲2(LayoutView2不拦截false)--儿子(MyTextView,onTouchEvent return false)--回传给父亲2(onTouchEvent return true)--结束
          * 33** 父亲1(LayoutView1不拦截false)---父亲2(LayoutView2不拦截false)--儿子(MyTextView,onTouchEvent return false)--回传给父亲2(onTouchEvent return false)--父亲1(onTouchEvent return true)--结束(如果都没处理不在执行UP ACTION)
          * 44** 父亲1(LayoutView1拦截true)--父亲1(onTouchEvent return true)--结束          (DOWN--DOWN(onTouchEvent)--UP(onTouchEvent))
          * 55** 父亲1(LayoutView1拦截false)--父亲2(LayoutView2拦截true)--父亲2(onTouchEvent return false)--父亲1(onTouchEvent return true)--结束      (DOWN1--DOWN2--DOWN(2 onTouchEvent)--DOWN(1 onTouchEvent)--UP(1 onTouchEvent))(1:父亲2,2:父亲2)
          * 
          * ***************************************************************************
          * 5.如果最终需要处理事件的view 的onTouchEvent()返回了true,那么后续事件将可以继续传递给该view的onTouchEvent()处理。 
          */
     
    下面给出一张处理的流程图:


     下附源代码:
  • 相关阅读:
    Java 多态
    java final 关键字
    Java @Override 注解
    java 代理 agency
    java 构造器(constructor)
    打赏功能的实现
    博客园设置类似sublime高亮代码
    Ant教程
    github(其他类似github)下载到本地配置
    OSI七层与TCP/IP五层网络架构详解
  • 原文地址:https://www.cnblogs.com/Free-Thinker/p/4673811.html
Copyright © 2011-2022 走看看