事件分发机制详解

来源:互联网 发布:网络平台推广 编辑:程序博客网 时间:2024/06/05 01:50

事件分发机制在Android是一个比较重要的知识体系,比较复杂,往往弄得一些初学者一头雾水,中在开发中充分的理解事件分发机制有助于我们解决滑动冲突问题,和一些自定义控件中的疑难问题,提高开发效率。接下里将详细介绍事件分发机制的整个过程和机理。

概述

当一个View被初始化结束后,经过一些列的处理,通过PhoneWindow把该View加载到Activity上面。当我们手指操作屏幕时候,是首先被当前的Activity捕获到的,交给Activity处理,Activity不具有事件的拦截能力,但是具有事件分发和事件响应的能力,若Activity没有子类View处理,则Activity处理;若Activity有子类View处理,则把事件分发给子类View处理。对于View处理事件则需要经过dispatchTouchEvent,onInterceptTouchEvent、onTouchEvent三个阶段,关系图如下:


事件分发

事件分发本身也具有消费的能力,当用户触摸屏幕时,被Activity捕获到,他把这个事件通过dispatchTouchEvent(MotionEvent ev)方法会将事件传递给最外层View的dispatchTouchEvent(MotionEvent ev)方法,该方法对事件进行分发。这里分为三种情况:

1、返回true:表示在本层不再进行分发,且已经进行消费掉,事件传递结束。如果不想让Activity的控件进行消费,可以重写Activity的dispatchTouchEvent方法,强制返回true。

2、返回false:表示在本层中不再进行事件的分发。如果当前的View的事件直接来自于Activity,则Activity的onTouchEvent进行消费;如果当前View的事件来自于父控件,则交给上层控件的onTouchEvent方法进行消费。

3、返回super.dispatchTouchEvent(ev):事件将分发给本层的事件拦截onInterceptTouchEvent 方法进行处理。

事件拦截
如上文所提到的,第三种情况会调用onInterceptTouchEvent(MotionEvent ev)方法会进行处理。分为三种情况:

1、返回true:表示将事件进行拦截,并将拦截到的事件交由本层控件 的 onTouchEvent 进行处理。

2、返回false:表示不拦截该事件,并将该事件交由子View的dispatchTouchEvent方法进行事件分发。

3、返回super.onInterceptTouchEvent(ev):默认表示不拦截该事件,并将该事件交由子View的dispatchTouchEvent方法进行事件分发。和返回false一样。

事件响应

以下三种情况下回执行onTouchEvent(MotionEvent ev)方法:

1、dispatchTouchEvent返回true

2、onInterceptTouchEvent返回true

3、onInterceptTouchEvent返回super.onInterceptTouchEvent(ev)

在回调onTouchEvent方法时候也分为三种情况:

1、返回true:表示onTouchEvent处理完事件后消费了此次事件。此时事件终结。

2、返回false:则表示不响应事件,那么该事件将会不断向上层View的onTouchEvent方法传递,直到某个View的onTouchEvent方法返回true,如果到了最顶层View还是返回false,那么认为该事件不消耗,则在同一个事件系列中,当前View无法再次接收到事件,该事件会交由Activity的onTouchEvent进行处理,如果Activity不处理,则这个事件就无响应。

3、返回super.dispatchTouchEvent(ev):表示不响应。和return false一致。

注意:

1、ViewGroup默认返回false,即不拦截任何事件。

2、不作为容器的View,如TextView,一旦接受到事件,就调用onTouchEvent方法,它们本身没有onInterceptTouchEvent方法。正常情况下,它们都会消耗事件(返回true),除非它们是不可点击的(clickable和longClickable都为false),那么就会交由父容器的onTouchEvent处理。

点击事件的流程分析

在系统为我们提供的一些空间中有的默认是可以点击的,如Button,有些是默认不可以点击的,例如:TextView。那么当我们给他设置了点击事件后他是如何执行的呢?OnTouchListener、onTouchEvent、OnClickListener、onTouch、onClick的执行顺序又是什么呢?这里分析一下。通过给view设置触摸事件,点击事件,重写onTouchEvent方法,我们进行日志的打印分析。




打印的日志如下:


当按下时候打印onTouch,onTouchEvent;取消的时候打印:onTouch,onTouchEvent,onClick。这里执行了两次事件:按下和取消所以onTouch,onTouchEvent才执行了两次,可以得出:

点击事件的执行顺序是:OnTouchListener的onTouch方法—->onTouchEvent-->OnClickListener的onClick方法

当设置onTouch返回值为true时候,打印日志如下:


可以看出View的onTouchEvent,onClick方法没有被执行,这个再次论证了上面的结论。

同样的方法我们这里改变onTouchEvent的返回值,来观察日志的打印情况,这里就不再次写出过程了,有兴趣的同学可以下来试试。通过以上分析,我们得出以下结论:

结论:

1、点击事件分发过程如下 dispatchTouchEvent—->OnTouchListener的onTouch方法—->onTouchEvent-->OnClickListener的onClick方法。所以三者优先级是onTouch->onTouchEvent->onClick。

2、平时给调用的setOnClickListener,优先级是最低的,所以onTouchEvent或OnTouchListener的onTouch方法如果返回true,则不响应onClick方法。

2、如果一个View同时监听了onTouch事件和onClick事件,则在onTouch里面应该返回false,否则点击事件就无法监听到。

3、View 的onTouchEvent 方法默认都会消费掉事件(返回true),除非它是不可点击的(clickable和longClickable同时为false。