Android 事件分发

在安卓四大组件中(Activity、Service、BroadCast、ContentProvider),最常用的当是Activity。因为Activity负责提供直观的页面并响应用户操作。在Activity的布局文件中,通过最外层的ViewGroup(布局)一层层嵌套、布局直至View(控件),组成了丰富多彩的用户页面。如QQ、微信等等。在开发这些页面过程中,难免会遇到一些事件冲突(说人话就是:你想点击的某个布局或控件,发现响应的是另一个布局或控件)的问题。呵呵,怎么办呢?由此引入我们接下来讨论的问题。

手机在响应用户的点击操作时,从Activity入口,遵循着一定的规则将对应的事件交由指定的ViewGroup或者View去响应(消费这个事件)。只有找出了各中规则,日后再次处理这类事件问题时,必定会得心应手。从程序的角度来看,Android提供三个方法处理事件问题dispatchTouchEvent(分发点击事件)、onInterceptTouchEvent(拦截点击事件),onTouchEvent(处理点击事件)。每个方法返回true或false表示是否处理它对应的职责。比如说,如果我拦截了事件,就表示自身要处理该事件,不让别的控件再能接收到事件信号。除了返回true或false之外,还能通过调用父类的方法执行父类的逻辑。简而言之,Activity、ViewGroup、View三个类处理事件,相关的方法依次是dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent以及每个方法的返回可以是true、false和super。其中注意:Activity和View没有拦截事件方法。

编写一个测试demo,布局文件中用LinearLayout嵌套RelativeLayout,最后在RelativeLayout中包含一个Button按钮。依次在每个事件处理方法中,输出log日志。点击按钮测试,通过日志信息分析事件分发流程。下图是布局效果。

为方便描述,定制命名规则:Activity简写A,LinearLayout简写L,RelativeLayout简写R,Button简写B,dispatchTouchEvent简写D,onInterceptTouchEvent简写I,onTouchEvent简写T,返回true简写T,返回false简写F,返回super简写S。如:ADS表示Activity中dispatchTouchEvent方法
return super。

测试方案一:ADS/ATS、LDS/LIS/LTS、RDS/RIS/RTS、BDS/BTS

日志如下:

04-01 12:44:44.402: D/Activity(1234): dispatchTouchEvent ACTION_DOWN
04-01 12:44:44.402: D/MyLinearLayout(1234): dispatchTouchEvent ACTION_DOWN
04-01 12:44:44.402: D/MyLinearLayout(1234): onInterceptTouchEvent ACTION_DOWN
04-01 12:44:44.402: D/MyRelativeLayout(1234): dispatchTouchEvent ACTION_DOWN
04-01 12:44:44.402: D/MyRelativeLayout(1234): onInterceptTouchEvent ACTION_DOWN
04-01 12:44:44.402: D/MyButton(1234): dispatchTouchEvent ACTION_DOWN
04-01 12:44:44.402: D/MyButton(1234): onTouchEvent ACTION_DOWN
04-01 12:44:44.506: D/Activity(1234): dispatchTouchEvent ACTION_UP
04-01 12:44:44.506: D/MyLinearLayout(1234): dispatchTouchEvent ACTION_UP
04-01 12:44:44.506: D/MyLinearLayout(1234): onInterceptTouchEvent ACTION_UP
04-01 12:44:44.506: D/MyRelativeLayout(1234): dispatchTouchEvent ACTION_UP
04-01 12:44:44.506: D/MyRelativeLayout(1234): onInterceptTouchEvent ACTION_UP
04-01 12:44:44.506: D/MyButton(1234): dispatchTouchEvent ACTION_UP
04-01 12:44:44.506: D/MyButton(1234): onTouchEvent ACTION_UP
04-01 12:44:44.506: D/Button(1234): 点击

整理出如下示意图:三色箭头实线,表示对应方法返回一个值会跳转到下一个方法。其中Button 返回true和返回super都会消费事件,只是返回true就不在就不再响应button的点击事件。

测试方案二:ADS/ATS、LDS/LIS/LTS、RDS/RIS/RTS、BDS/BTF

04-01 14:00:54.970: D/Activity(1387): dispatchTouchEvent ACTION_DOWN
04-01 14:00:54.970: D/MyLinearLayout(1387): dispatchTouchEvent ACTION_DOWN
04-01 14:00:54.970: D/MyLinearLayout(1387): onInterceptTouchEvent ACTION_DOWN
04-01 14:00:54.970: D/MyRelativeLayout(1387): dispatchTouchEvent ACTION_DOWN
04-01 14:00:54.970: D/MyRelativeLayout(1387): onInterceptTouchEvent ACTION_DOWN
04-01 14:00:54.970: D/MyButton(1387): dispatchTouchEvent ACTION_DOWN
04-01 14:00:54.970: D/MyButton(1387): onTouchEvent ACTION_DOWN
04-01 14:00:54.970: D/MyRelativeLayout(1387): onTouchEvent ACTION_DOWN
04-01 14:00:54.970: D/MyLinearLayout(1387): onTouchEvent ACTION_DOWN
04-01 14:00:54.970: D/Activity(1387): onTouchEvent ACTION_DOWN
04-01 14:00:55.066: D/Activity(1387): dispatchTouchEvent ACTION_UP
04-01 14:00:55.066: D/Activity(1387): onTouchEvent ACTION_UP

说明:Button 的onTouchEvent return false时,点击事件会返回到上一层视图。如果一直都没有控件处理这个事件就会交给Activitiy 的onTouchEvent消费。当再传入事件时,不会再按照之前的流程,每个空间均处理一次,而是直接给 Activity 的onTouchEvent消费。就是虚线所指。

测试方案三:ADS/ATS、LDS/LIS/LTS、RDS/RIS/RTS、BDT/BTF

04-01 14:12:47.918: D/Activity(1444): dispatchTouchEvent ACTION_DOWN
04-01 14:12:47.918: D/MyLinearLayout(1444): dispatchTouchEvent ACTION_DOWN
04-01 14:12:47.918: D/MyLinearLayout(1444): onInterceptTouchEvent ACTION_DOWN
04-01 14:12:47.918: D/MyRelativeLayout(1444): dispatchTouchEvent ACTION_DOWN
04-01 14:12:47.918: D/MyRelativeLayout(1444): onInterceptTouchEvent ACTION_DOWN
04-01 14:12:47.918: D/MyButton(1444): dispatchTouchEvent ACTION_DOWN
04-01 14:12:48.030: D/Activity(1444): dispatchTouchEvent ACTION_UP
04-01 14:12:48.030: D/MyLinearLayout(1444): dispatchTouchEvent ACTION_UP
04-01 14:12:48.030: D/MyLinearLayout(1444): onInterceptTouchEvent ACTION_UP
04-01 14:12:48.030: D/MyRelativeLayout(1444): dispatchTouchEvent ACTION_UP
04-01 14:12:48.030: D/MyRelativeLayout(1444): onInterceptTouchEvent ACTION_UP
04-01 14:12:48.030: D/MyButton(1444): dispatchTouchEvent ACTION_UP

说明:Button dispatchTouchEvent方法返回true,表示自身需要消费该事件。且不传递给onTouchEvent方法。

测试方案四:ADS/ATS、LDS/LIS/LTS、RDS/RIS/RTS、BDF/BTF

04-01 14:19:40.014: D/Activity(1502): dispatchTouchEvent ACTION_DOWN
04-01 14:19:40.014: D/MyLinearLayout(1502): dispatchTouchEvent ACTION_DOWN
04-01 14:19:40.014: D/MyLinearLayout(1502): onInterceptTouchEvent ACTION_DOWN
04-01 14:19:40.014: D/MyRelativeLayout(1502): dispatchTouchEvent ACTION_DOWN
04-01 14:19:40.014: D/MyRelativeLayout(1502): onInterceptTouchEvent ACTION_DOWN
04-01 14:19:40.014: D/MyButton(1502): dispatchTouchEvent ACTION_DOWN
04-01 14:19:40.014: D/MyRelativeLayout(1502): onTouchEvent ACTION_DOWN
04-01 14:19:40.014: D/MyLinearLayout(1502): onTouchEvent ACTION_DOWN
04-01 14:19:40.014: D/Activity(1502): onTouchEvent ACTION_DOWN
04-01 14:19:40.022: D/Activity(1502): dispatchTouchEvent ACTION_UP
04-01 14:19:40.022: D/Activity(1502): onTouchEvent ACTION_UP

说明:Button dispatchTouchEvent方法返回false,事件传递给父控件onTouchEvent方法。

测试方案五:ADS/ATS、LDS/LIS/LTS、RDS/RIS/RTT、BDF/BTF

04-01 14:26:03.306: D/Activity(1561): dispatchTouchEvent ACTION_DOWN
04-01 14:26:03.306: D/MyLinearLayout(1561): dispatchTouchEvent ACTION_DOWN
04-01 14:26:03.306: D/MyLinearLayout(1561): onInterceptTouchEvent ACTION_DOWN
04-01 14:26:03.306: D/MyRelativeLayout(1561): dispatchTouchEvent ACTION_DOWN
04-01 14:26:03.306: D/MyRelativeLayout(1561): onInterceptTouchEvent ACTION_DOWN
04-01 14:26:03.306: D/MyButton(1561): dispatchTouchEvent ACTION_DOWN
04-01 14:26:03.306: D/MyRelativeLayout(1561): onTouchEvent ACTION_DOWN
04-01 14:26:03.366: D/Activity(1561): dispatchTouchEvent ACTION_UP
04-01 14:26:03.366: D/MyLinearLayout(1561): dispatchTouchEvent ACTION_UP
04-01 14:26:03.366: D/MyLinearLayout(1561): onInterceptTouchEvent ACTION_UP
04-01 14:26:03.366: D/MyRelativeLayout(1561): dispatchTouchEvent ACTION_UP
04-01 14:26:03.366: D/MyRelativeLayout(1561): onTouchEvent ACTION_UP

说明:RelativeLayout 的onTouchEvent方法return true 消费了事件,下次事件生成时,就不传递给Button,直接交由RelativeLayout 的onTouchEvent方法处理。

测试方案六:ADS/ATS、LDS/LIS/LTS、RDS/RIS/RTF、BDF/BTF

04-01 14:39:20.794: D/Activity(1644): dispatchTouchEvent ACTION_DOWN
04-01 14:39:20.798: D/MyLinearLayout(1644): dispatchTouchEvent ACTION_DOWN
04-01 14:39:20.798: D/MyLinearLayout(1644): onInterceptTouchEvent ACTION_DOWN
04-01 14:39:20.798: D/MyRelativeLayout(1644): dispatchTouchEvent ACTION_DOWN
04-01 14:39:20.798: D/MyRelativeLayout(1644): onInterceptTouchEvent ACTION_DOWN
04-01 14:39:20.798: D/MyButton(1644): dispatchTouchEvent ACTION_DOWN
04-01 14:39:20.798: D/MyRelativeLayout(1644): onTouchEvent ACTION_DOWN
04-01 14:39:20.798: D/MyLinearLayout(1644): onTouchEvent ACTION_DOWN
04-01 14:39:20.798: D/Activity(1644): onTouchEvent ACTION_DOWN
04-01 14:39:20.874: D/Activity(1644): dispatchTouchEvent ACTION_UP
04-01 14:39:20.874: D/Activity(1644): onTouchEvent ACTION_UP

说明:RelativeLayout return false,就会将事件传递到上一层控件消费。其中,RelativeLayout onInterceptTouchEvent return false 表示事件也会分发到Button处理。

测试方案七:ADS/ATS、LDS/LIS/LTS、RDS/RIT/RTF、BDF/BTF

04-01 15:02:41.594: D/Activity(1739): dispatchTouchEvent ACTION_DOWN
04-01 15:02:41.594: D/MyLinearLayout(1739): dispatchTouchEvent ACTION_DOWN
04-01 15:02:41.594: D/MyLinearLayout(1739): onInterceptTouchEvent ACTION_DOWN
04-01 15:02:41.594: D/MyRelativeLayout(1739): dispatchTouchEvent ACTION_DOWN
04-01 15:02:41.594: D/MyRelativeLayout(1739): onInterceptTouchEvent ACTION_DOWN
04-01 15:02:41.594: D/MyRelativeLayout(1739): onTouchEvent ACTION_DOWN
04-01 15:02:41.594: D/MyLinearLayout(1739): onTouchEvent ACTION_DOWN
04-01 15:02:41.594: D/Activity(1739): onTouchEvent ACTION_DOWN
04-01 15:02:41.714: D/Activity(1739): dispatchTouchEvent ACTION_UP
04-01 15:02:41.714: D/Activity(1739): onTouchEvent ACTION_UP

说明:RelativeLayout onInterceptTouchEvent 返回true,表示RelativeLayout 拦截事件信息,Button不会响应事件,事件交由RelativeLayout onTouchEvent处理。

测试方案八:ADS/ATS、LDS/LIS/LTS、RDT/RIT/RTF、BDF/BTF

04-01 15:27:17.002: D/Activity(1907): dispatchTouchEvent ACTION_DOWN
04-01 15:27:17.002: D/MyLinearLayout(1907): dispatchTouchEvent ACTION_DOWN
04-01 15:27:17.002: D/MyLinearLayout(1907): onInterceptTouchEvent ACTION_DOWN
04-01 15:27:17.002: D/MyRelativeLayout(1907): dispatchTouchEvent ACTION_DOWN
04-01 15:27:17.058: D/Activity(1907): dispatchTouchEvent ACTION_UP
04-01 15:27:17.058: D/MyLinearLayout(1907): dispatchTouchEvent ACTION_UP
04-01 15:27:17.058: D/MyLinearLayout(1907): onInterceptTouchEvent ACTION_UP
04-01 15:27:17.058: D/MyRelativeLayout(1907): dispatchTouchEvent ACTION_UP

说明:RelativeLayout dispatchTouchEvent return true 表示自己消费事件,不再进行传递

测试方案九:ADS/ATS、LDS/LIS/LTS、RDF/RIT/RTF、BDF/BTF

04-01 15:32:12.138: D/Activity(1965): dispatchTouchEvent ACTION_DOWN
04-01 15:32:12.138: D/MyLinearLayout(1965): dispatchTouchEvent ACTION_DOWN
04-01 15:32:12.138: D/MyLinearLayout(1965): onInterceptTouchEvent ACTION_DOWN
04-01 15:32:12.138: D/MyRelativeLayout(1965): dispatchTouchEvent ACTION_DOWN
04-01 15:32:12.138: D/MyLinearLayout(1965): onTouchEvent ACTION_DOWN
04-01 15:32:12.138: D/Activity(1965): onTouchEvent ACTION_DOWN
04-01 15:32:12.250: D/Activity(1965): dispatchTouchEvent ACTION_UP
04-01 15:32:12.250: D/Activity(1965): onTouchEvent ACTION_UP

说明:RelativeLayout dispatchTouchEvent return false 表示不处理事件,交给上层页面处理。

测试方案十:ADT/ATS、LDS/LIS/LTS、RDF/RIT/RTF、BDF/BTF

04-01 15:43:24.558: D/Activity(2023): dispatchTouchEvent ACTION_DOWN
04-01 15:43:24.686: D/Activity(2023): dispatchTouchEvent ACTION_UP

说明:同ViewGroup和View的 dispatchTouchEvent 方法一样,return true 表示自己消费事件。不同的是,Activity 的dispatchTouchEvent方法return false 也表示自己消费事件。

测试方案十一:ADS/ATS、LDS/LIS/LTS、RDF/RIT/RTF、BDF/BTF

04-01 15:56:51.486: D/Activity(2149): dispatchTouchEvent ACTION_DOWN
04-01 15:56:51.486: D/MyLinearLayout(2149): dispatchTouchEvent ACTION_DOWN
04-01 15:56:51.486: D/MyLinearLayout(2149): onInterceptTouchEvent ACTION_DOWN
04-01 15:56:51.486: D/MyRelativeLayout(2149): dispatchTouchEvent ACTION_DOWN
04-01 15:56:51.486: D/MyLinearLayout(2149): onTouchEvent ACTION_DOWN
04-01 15:56:51.486: D/Activity(2149): onTouchEvent ACTION_DOWN
04-01 15:56:51.490: D/Activity(2149): dispatchTouchEvent ACTION_UP
04-01 15:56:51.490: D/Activity(2149): onTouchEvent ACTION_UP

说明:其实,最终只要传递到Activity的onTouchEvent 方法,都会交由它处理事件。

参照之前理解的思路,将整个示意图完善如下:

总结:

1.Activity 的dispatchTouchEvent方法,执行父类dispatchTouchEvent方法时,会将事件分发至ViewGroup,否则自身消费事件。

2.当事件再次传递到Activity 的onTouchEvent方法,表示页面中所有控件都不响应事件,由Activity处理。

3.ViewGroup和View 的dispatchTouchEvent方法,return true表示不分发事件,自身处理。return false就将事件传递给上层控件的onTouchEvent方法,并且不再响应上层控件传递过来的事件。

4.ViewGroup 的onInterceptTouchEvent方法return true表示拦截事件,将事件传递给自身的onTouchEvent方法处理。

5.View 的onTouchEvent 方法return false 表示不消费事件,将事件传递给上层控件的onTouchEvent方法。否则,消费事件。

6.ViewGroup的onTouchEvent 方法return true表示消费事件,否则将事件传递给上层控件或Activity的onTouchEvent方法处理。

7.当控件没有处理事件时,就不再接收下一个事件消息,虚线所示。

最后,祝各位程序猿/媛、码农、攻城狮们愚人节快乐。

时间: 2024-10-25 13:00:01

Android 事件分发的相关文章

Android事件分发机制详解:史上最全面、最易懂

前言 Android事件分发机制是每个Android开发者必须了解的基础知识 网上有大量关于Android事件分发机制的文章,但存在一些问题:内容不全.思路不清晰.无源码分析.简单问题复杂化等等 今天,我将全面总结Android的事件分发机制,我能保证这是市面上的最全面.最清晰.最易懂的 本文秉着"结论先行.详细分析在后"的原则,即先让大家感性认识,再通过理性分析从而理解问题: 所以,请各位读者先记住结论,再往下继续看分析: 文章较长,阅读需要较长时间,建议收藏等充足时间再进行阅读 目

Android事件分发机制总结

理解事件的分发机制,需要对View和ViewGroup事件的分发分别探讨.View和ViewGroup的区别,一个View控件是指它里面不能再包含子控件了,常见的如TextView.Button.ImageView等,而ViewGroup是继承自View的,但是它里面可以包含一些子控件,包括View或者嵌套的ViewGroup,常用的大部分布局都是ViewGroup组件,如LinearLayout.RelativeLayout.FrameLayout等. 首先要明白的是,当我们触摸一个控件时(不

Android事件分发机制

转载请注明出处:http://blog.csdn.net/chziroy/article/details/44401615 要理解Android事件分发机制,首先得了解几个概念,也算是总结,如果暂时看不懂也无妨,本文会讲解这几个问题. 1,点击屏幕,首先事件的传递从Activity的dispatchTouchEvent()方法开始. 2,关于Android事件分发机制,相关方法的方法有三个:onTouchEvent(),dispatchTouchEvent(),还有onInterceptTouc

Android事件分发学习应用-图片轮播实现

前一篇写到Android事件分发机制学习笔记,下面我们通过一个实例的应用来实践理解下Android事件分发的机制.我们这里来实现一个图片的轮播功能,最后顺便实现下图片的自动轮播. 我们的图片轮播是封装在一个ViewGroup里,当我们进行横向滑动的时候,我们需要阻止事件从ViewGroup往子控件分发,ViewGroup来消费我们当前的滑动图片何去何从.下面我们贴出我们的封装的ViewGroup的代码实现如下: public class ImageSwitcher extends ViewGro

图解 Android 事件分发机制

首发原文:http://mp.weixin.qq.com/s?__biz=MzI0MjE3OTYwMg==&mid=2649548149&idx=1&sn=709149df682c7d3a6e453c9ef0626a1f&chksm=f1180e08c66f871eb2e7e39e057a5b090214fd71adcd98aa36b3d7fcecf77ad5d08138c50131#rd 在Android开发中,事件分发机制是一块Android比较重要的知识体系,了解并熟

android事件分发介绍

Android事件分发 事件分发3个步骤 dispatchTouchEvent(event)派发 onInterceptTouchEvent(event)拦截 onTouchEvent(event) 处理 requestDisallowInterceptTouchEvent()设置父控件是否拦截事件 MotionEvent由 Activity获取到事件,传递到View,当前的View,派发-> 拦截 -> 处理. 当前Viwe派发了,onTouchEvent.在处理是否拦截. 如果拦截(tru

Android事件分发机制的学习

最近被Android事件分发机制折磨的很烦躁,网上各种博客资料看完觉得还是得自己写一篇,一方面加深理解,另一方面希望能帮助到也同样在学习相关知识的童鞋们. 话不多说,直接开整. 当用户的手指点击到屏幕,便是整个事件的开始. 首先获取到该事件的是view层的控制者Activity,具体怎么获得我们不得而知,在此也不追究,而继续我们的主题.Activity获得事件后便执行它自身的方法: public boolean dispatchTouchEvent(MotionEvent ev) { if (e

Android事件分发机制完全解析,带你从源码的角度彻底理解(上)

转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/9097463 其实我一直准备写一篇关于Android事件分发机制的文章,从我的第一篇博客开始,就零零散散在好多地方使用到了Android事件分发的知识.也有好多朋友问过我各种问题,比如:onTouch和onTouchEvent有什么区别,又该如何使用?为什么给ListView引入了一个滑动菜单的功能,ListView就不能滚动了?为什么图片轮播器里的图片使用Button而不用Ima

android 事件分发机制(图文详解)

在Android开发中,事件分发机制是一块Android比较重要的知识体系,了解并熟悉整套的分发机制有助于更好的分析各种点击滑动失效问题,更好去扩展控件的事件功能和开发自定义控件,同时事件分发机制也是Android面试必问考点之一,如果你能把下面的一些事件分发图当场画出来肯定加分不少.废话不多说,总结一句:事件分发机制很重要. Android 事件分发流 关于Android 事件分发机制网上的博文很多,但是很多都是写个Demo然后贴一下输出的Log或者拿源码分析,然后一堆的注释和说明,如果用心的

android事件分发(二)

非常早之前写过一篇android事件分发的博客,主要写的是它是怎样分发的,具体非常多原理的东西都没有涉及到.今天就从源代码看android怎样控制它的分发机制. 鉴于手机屏幕的限制,所以android选择了分层的方式布局,这就引出了今天的主题--事件分发 当你点击一个控件或者某个空白区域时,怎样确定你点击的位置,事件又是怎样传递到这里的,相信看过上篇博客的都知道怎样传递了,以下就開始看源代码 public boolean dispatchTouchEvent(MotionEvent event)