首页 > 代码库 > Android6.0触摸事件分发机制解读

Android6.0触摸事件分发机制解读

    本篇博文是Android触摸事件分发机制系列博文的第一篇,带领大家从全局掌握Android触摸事件分发机制。特别声明的是,本源码解读是基于最新的Android6.0版本。

(一)Android6.0源码解读之View点击事件分发机制

(二)Android6.0源码解读之ViewGroup点击事件分发机制

(三)Android6.0源码解读之Activity点击事件分发机制

为什么要解读触摸事件分发机制

1.掌握View事件分发机制
2.为解决View滑动冲突提供理论支持
3.了解Android最新源码改动

Touch触摸事件

    在Android中Touch触摸事件主要包括点击(onClick)、长按(onLongClick)、拖拽(onDrag)、滑动(onScroll)等,点击又包括单击和双击,另外还包括单指操作和多指操作。其中Touch的第一个状态是 ACTION_DOWN,表示按下了屏幕后,touch将会有后续事件,比如移动、抬起等,一个Action_DOWN,一个ACTION_UP,许多个ACTION_MOVE,就构成了Android中众多的事件。所有的操作事件首先必须执行的是按下操作(ACTIONDOWN),之后所有的操作都是以此作为前提,当按下操作完成后,接下来可能是一段移动(ACTIONMOVE)然后抬起(ACTION_UP),或者是按下操作执行完成后没有移动就直接抬起。

● 按下(ACTION_DOWN)
● 移动(ACTION_MOVE)
● 抬起(ACTION_UP)
● 取消手势(ACTION_CANCEL)
● 滑出屏幕(ACTION_OUTSIDE)

触摸事件分发机制涉及的三个重要方法

public boolean dispatchTouchEvent(MotionEvent ev)

dispatchTouchEvent用来进行事件的分发。如果事件能够传递给当前的View,那么此方法一定会被调用,返回结果受当前View的onTouchEvent和下级View的dispatchTouchEvent方法的影响,表示是否消耗当前事件。

public boolean onInterceptTouchEvent(MotionEvent event)

onInterceptTouchEvent是ViewGroup提供的方法,用来判断是否拦截某个事件,如果当前View拦截了某个事件,那么在同一个事件序列当中,此方法不会被再次调用,返回结果表示是否拦截当前事件。默认返回false,返回true表示拦截。

public boolean onTouchEvent(MotionEvent event)

onTouchEvent在dispatchTouchEvent方法中调用,用来处理点击事件,返回结果表示是否消耗当前的事件,如果不消耗,则在同一个事件序列中,当前View无法再次接受到事件。view中默认返回true,表示消费了这个事件。

这三个重要方法的分布情况

在View中包含以下两个方法:

public boolean dispatchTouchEvent(MotionEvent ev);
public boolean onTouchEvent(MotionEvent ev);

在ViewGroup中包含以下三个方法:

public boolean dispatchTouchEvent(MotionEvent ev);
public boolean onInterceptTouchEvent(MotionEvent ev);
public boolean onTouchEvent(MotionEvent ev);

在Activity中包含以下两个方法:

public boolean dispatchTouchEvent(MotionEvent ev);
public boolean onTouchEvent(MotionEvent ev);

技术分享

Android触摸事件分发流程图

技术分享

Android触摸事件流程总结

1.一个事件序列是指从手指触摸屏幕开始,到手指离开屏幕结束,这个过程中产生的一系列事件。同一个事件序列是以ACTION_DOWN事件开始,中间含有数量不定的MOVE事件,最终以ACTION_UP事件结束。

2.事件传递的顺序是:Activity->Window->View,即事件总是先传递给Activity,然后在传递给Window,最后在传递给View,顶级View接收到事件后,就会按照事件分发机制去分发事件。

3.事件的传递过程是由外向内的,即事件总是由父元素分发给子元素。

4.正常情况下,一个事件序列只能被一个View拦截且消耗。一旦一个元素拦截了某次事件,那么同一个事件序列内的所有事件都会直接交给它处理,因此同一个事件序列中的事件不能分别由两个View同时处理,但是通过特殊手段可以做到,比如一个View将本该自己处理的事件通过onTouchEvent强行传递给其他View处理。

5.某个View一旦开始处理事件,如果它不消耗ACTION_DOWN事件,那么同一事件序列的其他事情都不会再交给它来处理,并且事件将重新交给它的父容器去处理(调用父容器的onTouchEvent方法);如果它消耗ACTION_DOWN事件,但是不消耗其他类型事件,那么这个点击事件会消失,父容器的onTouchEvent方法不会被调用,当前view依然可以收到后续的事件,但是这些事件最后都会传递给Activity处理。

6.Android点击事件分发是到达顶级View后(一般是ViewGroup),会调用ViewGroup的dispatchTouchEvent方法,其中它的onInterceptTouchEvent方法如果返回true,则会对事件传递进行拦截,事件由ViewGroup处理;如果onInterceptTouchEvent方法返回false,则代表不对事件进行拦截,默认返回false。则此时子View中的dispatchTouchEvent方法将被调用,到此,事件已经由顶级View传递给了下一层的View,接下来的过程是一个递归循环的过程,和顶级View事件分发过程是一致的,直到完成整个事件分发。

针对View、ViewGroup、Activity中的事件分发机制源码解读

各位童鞋可以参考下面链接进行系统学习

(一)Android6.0源码解读之View点击事件分发机制

(二)Android6.0源码解读之ViewGroup点击事件分发机制

(三)Android6.0源码解读之Activity点击事件分发机制

<script type="text/javascript"> $(function () { $(‘pre.prettyprint code‘).each(function () { var lines = $(this).text().split(‘\n‘).length; var $numbering = $(‘
    ‘).addClass(‘pre-numbering‘).hide(); $(this).addClass(‘has-numbering‘).parent().append($numbering); for (i = 1; i <= lines; i++) { $numbering.append($(‘
  • ‘).text(i)); }; $numbering.fadeIn(1700); }); }); </script>

    Android6.0触摸事件分发机制解读