首先,看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

  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

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

第二层布局LayoutView2.java

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

自定义MyTextView.java

  1. <span style="font-size: small;">package com.hao;
  2. import android.content.Context;
  3. import android.util.AttributeSet;
  4. import android.util.Log;
  5. import android.view.MotionEvent;
  6. import android.view.View;
  7. import android.widget.TextView;
  8. public class MyTextView extends TextView {
  9. private final String TAG = "MyTextView";
  10. public MyTextView(Context context, AttributeSet attrs) {
  11. super(context, attrs);
  12. Log.e(TAG,TAG);
  13. }
  14. @Override
  15. public boolean onTouchEvent(MotionEvent ev) {
  16. int action = ev.getAction();
  17. switch(action){
  18. case MotionEvent.ACTION_DOWN:
  19. Log.e(TAG,"onTouchEvent action:ACTION_DOWN");
  20. break;
  21. case MotionEvent.ACTION_MOVE:
  22. Log.e(TAG,"onTouchEvent action:ACTION_MOVE");
  23. break;
  24. case MotionEvent.ACTION_UP:
  25. Log.e(TAG,"onTouchEvent action:ACTION_UP");
  26. break;
  27. case MotionEvent.ACTION_CANCEL:
  28. Log.e(TAG,"onTouchEvent action:ACTION_CANCEL");
  29. break;
  30. }
  31. return false;
  32. //       return true;
  33. }
  34. public void onClick(View v) {
  35. Log.e(TAG, "onClick");
  36. }
  37. public boolean onLongClick(View v) {
  38. Log.e(TAG, "onLongClick");
  39. return false;
  40. }
  41. }
  42. </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()处理。 
      */
 
下面给出一张处理的流程图:

 下附源代码:

Android事件模型之interceptTouchEvnet ,onTouchEvent关系正解的更多相关文章

  1. Android 事件模型

    本文内容 基于监听的事件模型 基于回调的事件模型 Android 支持两种事件模型,基于监听的事件模型和基于回调的事件模型. 基于监听的事件模型 基于监听的事件模型是一种委托式的,更"面向对 ...

  2. Android事件机制之二:onTouch详解

    <Android事件机制之一:事件传递和消费>一文总结了Android中的事件传递和消费机制. 在其中对OntachEvent中的总结中,不是很具体.本文将主要对onTach进行总结. o ...

  3. 对于android触摸事件模型的一些理解

    body{ font-family: "Microsoft YaHei UI","Microsoft YaHei",SimSun,"Segoe UI& ...

  4. Android进阶——Android事件分发机制之dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent

    Android事件分发机制可以说是我们Android工程师面试题中的必考题,弄懂它的原理是我们避不开的任务,所以长痛不如短痛,花点时间干掉他,废话不多说,开车啦 Android事件分发机制的发生在Vi ...

  5. 【朝花夕拾】Android自定义View篇之(六)Android事件分发机制(中)从源码分析事件分发逻辑及经常遇到的一些“诡异”现象

    前言 转载请注明,转自[https://www.cnblogs.com/andy-songwei/p/11039252.html]谢谢! 在上一篇文章[[朝花夕拾]Android自定义View篇之(五 ...

  6. 【朝花夕拾】Android自定义View篇之(五)Android事件分发机制(上)Touch三个重要方法的处理逻辑

    前言 转载请注明,转自[https://www.cnblogs.com/andy-songwei/p/10998855.html]谢谢! 在自定义View中,经常需要处理Android事件分发的问题, ...

  7. Android事件分发机制三:事件分发工作流程

    前言 很高兴遇见你~ 本文是事件分发系列的第三篇. 在前两篇文章中,Android事件分发机制一:事件是如何到达activity的? 分析了事件分发的真正起点:viewRootImpl,Activit ...

  8. Android事件分发机制四:学了事件分发有什么用?

    " 学了事件分发,影响我CV大法吗?" " 影响我陪女朋友的时间" " ..... " 前言 Android事件分发机制已经来到第四篇了,在 ...

  9. 讲讲Android事件拦截机制

    简介 什么是触摸事件?顾名思义,触摸事件就是捕获触摸屏幕后产生的事件.当点击一个按钮时,通常会产生两个或者三个事件--按钮按下,这是事件一,如果滑动几下,这是事件二,当手抬起,这是事件三.所以在And ...

随机推荐

  1. js this [转]

    this是js的一个关键字,随着函数使用场合不同,this的值会发生变化.但是总有一个原则,那就是this指的是调用函数的那个对象. 1.纯粹函数调用. function test() { this. ...

  2. projecteuler之58题Spiral primes

    package com.android; public class SpiralPrimes { public static void main(String args[]) { long numPr ...

  3. LinuxC安装gcc

    使用centos进行C编程的时候使用gcc hello.c提示 bash:gcc:command not found 此时需要给Linux安装gcc命令如下 1 yum -y install gcc ...

  4. asp.net core+ef core

    asp.net core+ef core 官方的文档https://docs.asp.net/en/latest/tutorials/first-mvc-app/start-mvc.html 先来看一 ...

  5. 系统运维-hub, repeater, switch, router初览

    repeater, hub, switch, router都是针对与osi的7层网络模型的不同层而产生的设备,逐一概览如下: repeater:中继器 是网络物理层的一种连接设备,工作在osi的物理层 ...

  6. Qt技巧:Win7下打包发布Qt程序(解释的比较清楚,把exe和dll伪装合并成一个文件)

    转自:http://www.stardrad.com/blog/qt-5%E7%A8%8B%E5%BA%8F%E5%9C%A8windows%E4%B8%8A%E7%9A%84%E5%8F%91%E5 ...

  7. 数据切分——MySql表分区概述

    定义:         表的分区指根据可以设置为任意大小的规则,跨文件系统分配单个表的多个部分.实际上,表的不同部分在不同的位置被存储为单独的表.用户所选择的.实现数据分割的规则被称为分区函数,这在M ...

  8. 顺序队列之C++实现

    下面介绍下用C++实现的顺序队列,在VC6下调试通过. 1.文件组织形式 2.sq.h顺序队列类的说明 #ifndef _SQ_H_ #define _SQ_H_ typedef int dataTy ...

  9. Failed to load the JNI shared library

    解决Eclipse无法打开"Failed to load the JNI shared library" 这是由于JDK配置错误所导致的现象. 一般说来,新购笔记本会预装64位的w ...

  10. levelDB跳表实现

    跳表的原理就是利用随机性建立索引,加速搜索,并且简化代码实现难度.具体的跳表原理不再赘述,主要是看了levelDB有一些实现细节的东西,凸显自己写的实现不足之处. 去除冗余的key template& ...