前言

前面有两篇博客从源码角度分析了Android中View的触摸事件处理和ViewGroup的触摸事件传递过程,对于初学者来说可能直接从源码了解Android触摸事件有点门槛,那么这篇博客我们不分析源码,尽量用简介的语言和简单的例子来详细解释Android触摸事件的处理和触摸事件传递的过程。

Android触摸事件流程简述

这里我将触摸事件理解为两部分:

  1. 触摸事件的传递过程
  2. 触摸事件的处理过程

触摸事件的传递过程

我们知道Activity的视图结构是自上而下的树形结构,而一个典型的触摸事件是从Activity开始,传递到Activity的根视图,然后经过层层ViewGroup,最后传递给某一个具体的View或者ViewGroup去处理。这就是触摸事件的传递过程,所以Android触摸事件的传递过程是自上而下的。犹如这么一个过程Activity–>ViewGroup–>View,只有上一个视图没有中断该触摸事件传递,下一个视图才能接收到该触摸事件。那么疑问来了,什么情况下触摸事件会中断传递呢?什么时候不中断传递?稍后解释。

触摸事件的处理过程

而触摸事件的处理过程却是自下而上的,怎么理解呢? 我们先建一个模型,比如有一个触摸事件传递过程如下:Activity–>ViewGroup–>View,那么此次触摸事件最先由View来处理,如果View没有处理掉该触摸事件,则由其父视图ViewGroup来处理该触摸事件,如果ViewGroup还没有处理掉该触摸事件,最后由当前Activity来处理该触摸事件。因此触摸事件的处理是自下而上的,只有下面的视图没有处理掉此次触摸事件,上一层视图才有机会去处理该触摸事件。那么疑问来了,什么情况下触摸事件处理掉了?什么情况下又没有处理掉?稍后解释。

触摸事件相关的方法

我们知道在View中有dispatchTouchEvent和onTouchEvent两个方法和触摸事件相关,其实在Activity中同样也有这两个方法。而在ViewGroup中除了以上两个方法之外还有一个onInterceptTouchEvent方法用于是否拦截触摸事件。而以上三个方法的返回值都是布尔类型,返回值决定触摸事件的传递是否被拦截,或者触摸事件是否被处理掉。这里直接给出一个结论就是当前视图的dispatchTouchEvent方法返回值为false表示触摸事件没有被处理掉,他的父视图就该去处理此次触摸事件,相反当返回值为true时,表示该视图处理掉了触摸事件,其父View就没有机会处理触摸事件了。如果ViewGroup中的onInterceptTouchEvent返回值为true表示拦截触摸事件,其子View就无法接收到触摸事件,也就没有机会去处理触摸事件了。系统默认onInterceptTouchEvent方法返回false,表示不拦截触摸事件。

View的触摸事件

在View中与触摸事件有关的方法有dispatchTouchEvent,onTouch和onTouchEvent方法。触摸事件会先调用dispatchTouchEvent方法,如果用户设置了onTouchListener触摸监听事件的话再调用onTouch方法,最后当onTouch方法返回false时,才会去调用onTouchEvent方法,否则触摸事件在View里面处理结束。而onTouch和onTouchEvent方法的返回值会决定dispatchTouchEvent方法的返回值。情况如下:

1.如果用户设置了onTouchListener触摸监听,且监听的回调方法返回为true时,该View的触摸事件处理结束,dispatchTouchEvent方法返回true。

2.如果用户未设置触摸监听事件或者监听回调方法返回false,则dispatchTouchEvent的返回值由 onTouchEvent方法的返回值决定。onTouchEvent方法返回true则dispatchTouchEvent方法返回false,反之。

dispatchTouchEvent方法的返回值决定当前View是否消费掉此次触摸事件。如果dispatchTouchEvent返回true表示此次触摸事件消费掉了,其父View就没有机会来处理该触摸事件了。如果dispatchToucEvent返回false,则表示该View没有消费掉此次触摸事件,该触摸事件会交给其父View来处理。

详解Android 触摸事件处理和传递过程的来龙去脉_第1张图片

ViewGroup触摸事件

由于ViewGroup继承自View,ViewGroup除了有dispatchTouchEvent和onTouchEvent方法还有一个onInterceptTouchEvent方法,该方法用于是否拦截触摸事件。

用户可以重写该方法,当返回true时,表示拦截此次触摸事件,不让触摸事件向下传递,也就是它的子View无法接收到触摸事件,也就无法处理触摸事件了。当返回false时,表示不拦截触摸事件,让其子View可以接收到触摸事件并有机会处理。

值得注意的是,如果其子视图不想被其父视图拦截触摸事件怎么办?android给子视图提供了getParent().requestDisallowInterceptTouchEvent(true);方法用来请求父视图不拦截该该子视图的触摸事件,也就是不管父视图ViewGroup的onInterceptTouchEvent方法返回什么值,该子视图都能接收到触摸事件。

在ViewGroup中重写View中的dispatchTouchEvent方法,该方法用于分发触摸事件,如果onInterceptTouchEvent方法返回false,则触摸事件就会传递给其子View的dispatchTouchEvent方法处理。

而如果其子View消费掉了此次触摸事件则该触摸事件到此结束,ViewGroup没有机会去处理该触摸事件了。

如果其子View没有消费掉此次触摸事件,则触摸事件由其自己处理,ViewGroup就会调用其父类中的dispatchTouchEvent方法,由于ViewGroup的父类是View,所以此处的处理过程和View触摸事件处理过程一样。

详解Android 触摸事件处理和传递过程的来龙去脉_第2张图片

Activity的触摸事件

你是否到现在还不知道Android处理触摸事件的入口在哪里?其实整个Android触摸事件处理入口在Activity类中的dispatchTouchEvent方法中,只不过我们几乎不去重写Activity#dispatchTouchEvent方法,那么今天我们简单了解下Activity的触摸事件传递和处理。Activity类中也有和View同样的方法dispatchTouchEvent和onTouchEvent两个方法。

1.Activity#dispatchTouchEvent方法是触摸事件的入口,用于接收用户触摸事件,并且将触摸事件分发给当前Activity的根视图。
2.Activity#onTouchEvent方法在Activity的根视图没有消费掉此次用户的触摸事件时调用。

那么什么时候Activity的触摸事件会传递下去呢?只要我们不去重写Activity的dispatchTouchEvent方法,触摸事件是会顺利传递下去的。也就是说Android系统默认在Activity中无条件执行dispatchTouchEvent方法来接受触摸事件,除非你重写该方法。言外之意就是当你想拦截整个触摸事件传递过程时,你可以重写Activity中的dispatchTouchEvent方法。

那么什么时候Activity可以处理此次的触摸事件呢?我们知道只有下一层视图没有处理掉该触摸事件Activity才有机会。也就是ViewGroup的dispatchTouchEvent方法返回false时,Activity才会去调用onTouchEvent方法处理触摸事件。

总结

在没有 重写任何方法的情况下,触摸事件的派遣将不会被截断,从 Activity 的根视图,自上而下的派遣到叶子 View ,然后调用该 View 的 onTouchEvent() (如果注册了监听器的话,则优先调用 OnTouchListener.onTouch() ,返回 false 才会再调用 onTouchEvent() )。如果该 View 不能处理事件( onTouchEvent() 返回了 false ),其父视图继续尝试处理,直到最后,调用 Activity 的 onTouchEvent() 方法。另外,值得注意的是,如果没有响应一个手势的开始事件 ( ACTION_DOWN ),则不会接到该手势的后续事件。

View和ViewGroup触摸事件处理传递详细篇请看我的另外两篇博客:
Android View触摸事件传递机制
Android ViewGroup 触摸事件传递机制

更多相关文章

  1. Android退出程序(三)——Android事件总线
  2. Android View onMeasure 方法
  3. Android Studio 3.0以后打包修改文件名方法
  4. 【Android】android开发过程遇到的问题以及解决方法总结
  5. android图片压缩方法
  6. Android处理各种触摸事件
  7. android ndk 入门2 - 基本方法实现

随机推荐

  1. ANDROID备份
  2. Android(安卓)几个Info系列类的总结
  3. android popupwindow的使用与讲解
  4. android多语言与国际化(记录)
  5. [置顶] Canvas开篇之drawBitmap方法讲解
  6. Android(安卓)ActionBar的基本用法
  7. Android(安卓)借助Stetho在Chrome上调试A
  8. Doze和App Standby的优化(API23)
  9. Android(安卓)NDK r5 windows系统上安装
  10. 【ADT】亲测、有图goagent解决ADT下载过