`
guojianhui0906
  • 浏览: 48255 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

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事件均返回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;
    }
}

分享到:
评论

相关推荐

    android事件2-onInterceptTouchEvent和onTouchEvent调用时序

    在Android开发中,理解和掌握`onInterceptTouchEvent`与`onTouchEvent`的调用时序至关重要,因为它们是实现触摸事件处理的关键。这两个方法都属于Android的触摸事件处理机制,涉及到了ViewGroup与子View之间的事件...

    Android中touch事件传递测试demo

    onInterceptTouchEvent和onTouchEvent调用时序详解 测试demo 详细介绍请移步:http://blog.csdn.net/yiranxinshou/article/details/9201833

    Touch事件案例

    "Touch事件案例"主要关注的是`onInterceptTouchEvent`和`onTouchEvent`这两个方法的调用时序,它们是处理触摸事件的关键组件,尤其在复杂的布局结构中,理解它们的工作原理对于优化用户界面和交互至关重要。...

    基于微信小程序的社区门诊管理系统php.zip

    基于Php语言设计并实现了微信小程序的社区门诊管理系统。该小程序基于B/S即所谓浏览器/服务器模式,选择MySQL作为后台数据库去开发并实现一个以微信小程序的社区门诊为核心的系统以及对系统的简易介绍。 用户注册,在用户注册页面通过填写账号、密码、确认密码、姓名、性别、手机、等信息进行注册操作; 用户登录,用户通过登录页面输入账号和密码,并点击登录进行小程序登录操作。 用户登陆微信端后,可以对首页、门诊信息、我的等功能进行详细操作 门诊信息,在门诊信息页面可以查看科室名称、科室类型、医生编号、医生姓名、 职称、坐诊时间、科室图片、点击次数、科室介绍等信息进行预约挂号操作 检查信息,在检查信息页面可以查看检查项目、检查地点、检查时间、检查费用、账号、姓名、医生编号、医生姓名、是否支付、审核回复、审核状态等信息进行支付操作

    白色大气风格的设计师作品模板下载.zip

    白色大气风格的设计师作品模板下载.zip

    工程经济学自考必备软件下载

    工程经济学自考必备软件下载

    UML课程设计报告.doc

    UML课程设计报告.doc

    白色大气风格响应式彩绘精品水果网站模板.zip

    白色大气风格响应式彩绘精品水果网站模板.zip

    白色简洁风格的别墅整站网站模板.zip

    白色简洁风格的别墅整站网站模板.zip

    白色简洁风格的APP展示动态源码下载.zip

    白色简洁风格的APP展示动态源码下载.zip

    VB+access电表管理系统(系统+论文+参考文献)(2024qu).7z

    1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于计算机科学与技术等相关专业,更为适合;

    白色大气风格的雪山旅游景区CSS3网站模板.zip

    白色大气风格的雪山旅游景区CSS3网站模板.zip

    基于python开发的大模型调用基础框架(源码)

    介绍 基于python开发的大模型调用基础框架(源码) 使用说明 修改配置文件 cd config vim __init__.py # 在配置文件中添加大模型调用地址,模型名称,API_KEY等配置 启动应用 应用启动分为两种模式,命令行模式和web模式 命令行模式 python main.py cli web模式 python main.py api

    基于JavaWeb的小区物业管理系统源代码+数据库

    基于JavaWeb的小区物业管理系统源代码+数据库 负责数据库的设计和界面的设计和实现; 界面使用 BootStrap 框架,页面自适应效果,修改页面后实现各个功能模块的布局; 负责实现用户登录注册,查看小区活动公告、水电费查询、车费查询信息; 采用的技术:采用 MVC 架构,数据库用 MySql;

    白色简单风格的商务企业网站模板下载.zip

    白色简单风格的商务企业网站模板下载.zip

    数据分析-29-260万用户大型家电和电子产品购买分析(包含数据代码)

    1. 平台在家电和电子产品方面的营运情况如何? 2. 哪些品牌和类别销量最高? 3. 用户消费规律 4. 哪些是我们的重点用户? 5. 平台有哪些优势和不足,需要如何改进?

    全平台数据库管理工具MySQL

    全平台数据库管理工具, 支持 ClickHouse, Presto, Trino, MySQL, PostgreSQL, Apache Druid, ElasticSearch...

    白色大气风格的旅游整站网站模板.zip

    白色大气风格的旅游整站网站模板.zip

    STM32F030单片机控制蜂鸣器.zip

    1、嵌入式物联网单片机项目开发例程,简单、方便、好用,节省开发时间。 2、代码使用KEIL 标准库开发,当前在STM32F030C8T6运行,如果是STM32F030其他型号芯片,依然适用,请自行更改KEIL芯片型号以及FLASH容量即可。 3、软件下载时,请注意keil选择项是jlink还是stlink。 4、有偿指导v:wulianjishu666; 5、如果接入其他传感器,请查看账号发布的其他资料。 6、单片机与模块的接线,在代码当中均有定义,请自行对照。 7、若硬件有差异,请根据自身情况调整代码,程序仅供参考学习。 8、代码有注释说明,请耐心阅读。 9、编译时请注意提示,请选择合适的编译器版本。

    【信息融合】基于matlab多维卡尔曼滤波器传感器信息融合(含GPS)【含Matlab源码 9980期】含报告.zip

    Matlab领域上传的视频均有对应的完整代码,皆可运行,亲测可用,适合小白; 1、代码压缩包内容 主函数:main.m; 调用函数:其他m文件;无需运行 运行结果效果图; 2、代码运行版本 Matlab 2019b;若运行有误,根据提示修改;若不会,私信博主; 3、运行操作步骤 步骤一:将所有文件放到Matlab的当前文件夹中; 步骤二:双击打开main.m文件; 步骤三:点击运行,等程序运行完得到结果; 4、仿真咨询 如需其他服务,可私信博主; 4.1 博客或资源的完整代码提供 4.2 期刊或参考文献复现 4.3 Matlab程序定制 4.4 科研合作

Global site tag (gtag.js) - Google Analytics