Android进阶——Android事件分发机制之dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent
- 格式:doc
- 大小:248.00 KB
- 文档页数:13
Android的事件分发一、Touch事件和绘制事件的异同之处Touch事件和绘制事件很类似,都是由ViewRoot派发下来的,但是不同之处在绘制事件是由应用中的某个View发起请求,一层一层上传到ViewRoot,再有ViewRoot下发绘制,传递canvas给所有子View让其绘制自身,绘制好后,再通知WMS进行画到屏幕上。
而Touch 事件是由硬件捕获到触摸后由系统传递给应用的ViewRoot,再由ViewRoot往下一层一层传递。
他们的处理过程都是自上而下的分发,但是绘制多了一层自下往上的请求。
事件存在消耗,事件的处理方法都会返回一个boolean值,如果该值为true,则本次事件下发将会终止。
二、MotionEvent1、MotionEvent对象的产生系统有一个线程在循环收集屏幕硬件信息,当用户触摸屏幕时,该线程会把从硬件设备收集到的信息封装成一个MotionEvent对象,然后把该对象存放到一个消息队列中。
系统的另一个线程循环的读取消息队列中的MotionEvent,然后交给WMS去派发,WMS 把该事件派发给当前处于活动的Activity,即处于活动栈最顶端的Activity。
这就是一个先进先出的消费者和生产者的模板,一个线程不停的创建MotionEvent对象放入队列中,另一个线程不断的从队列中取出MotionEvent对象进行分发。
当用户的手指从接触屏幕到离开屏幕,是一个完整的触摸事件,在该事件中,系统会不断收集事件信息封装成MotionEvent对象。
收集的间隔时间取决于硬件设备,例如屏幕的灵敏度以及cpu的计算能力。
目前的手机一般在20毫秒左右。
MotionEventCompat.getActionMasked()2、MotionEvent对象详解MotionEvent对象包含了触摸事件的时间、位置、面积、压力、以及本次事件的Dwon发生的时间。
MotionEvent常用的Action分为5种:Down 、Up、Move、Cancel、OutSideMotionEvent中我们常用的方法就是获取点击的坐标,因为这是与我们操作息息相关的。
一、了解Activity的构成一个Activity包含了一个Window对象,这个对象是由PhoneWindow来实现的。
PhoneWindow将DecorView作为整个应用窗口的根View,而这个DecorView又将屏幕划分为两个区域:一个是TitleView,另一个是ContentView,而我们平时所写的就是展示在ContentView中的,下图表示Activity的构成。
二、触摸事件的类型触摸事件对应的是MotionEvent类,事件的类型主要有如下三种:•ACTION_DOWN•ACTION_MOVE(移动的距离超过一定的阈值会被判定为ACTION_MOVE操作) •ACTION_UP三、事件传递的三个阶段•分发(dispatchTouchEvent):方法返回值为true表示事件被当前视图消费掉;返回为super.dispatchTouchEvent表示继续分发该事件。
•拦截(onInterceptTouchEvent):方法返回值为true表示拦截这个事件并交由自身的onTouchEvent方法进行消费;返回false表示不拦截,需要继续传递给子视图。
如果return super.onInterceptTouchEvent(ev),事件拦截分两种情况:1.如果该View(ViewGroup)存在子View且点击到了该子View, 则不拦截, 继续分发给子View 处理, 此时相当于return false。
2.如果该View(ViewGroup)没有子View或者有子View但是没有点击中子View(此时ViewGroup 相当于普通View), 则交由该View的onTouchEvent响应,此时相当于return true。
注意:一般的LinearLayout、 RelativeLayout、FrameLayout等ViewGroup默认不拦截,而ScrollView、ListView等ViewGroup则可能拦截,得看具体情况。
Android 编程下Touch 事件的分发和消费机制Android 中与Touch 事件相关的方法包括:dispatchTouchEvent(MotionEvent ev)、onInterceptTouchEvent(MotionEvent ev)、onTouchEvent(MotionEvent ev);能够响应这些方法的控件包括:ViewGroup、View、Activity。
方法与控件的对应关系如下表所示:从这张表中我们可以看到ViewGroup 和View 对与Touch 事件相关的三个方法均能响应,而Activity 对 onInterceptTouchEvent(MotionEvent ev) 也就是事件拦截不进行响应。
另外需要注意的是View 对 dispatchTouchEvent(MotionEvent ev) 和 onInterceptTouchEvent(MotionEvent ev) 的响应的前提是可以向该View 中添加子View,如果当前的View 已经是一个最小的单元View(比如TextView),那么就无法向这个最小View 中添加子View,也就无法向子View 进行事件的分发和拦截,所以它没有 dispatchTouchEvent(MotionEvent ev) 和 onInterceptTouchEvent(MotionEvent ev),只有onTouchEvent(MotionEvent ev)。
一、Touch 事件分析▐事件分发:public boolean dispatchTouchEvent(MotionEvent ev)Touch 事件发生时 Activity 的 dispatchTouchEvent(MotionEvent ev) 方法会以隧道方式(从根元素依次往下传递直到最内层子元素或在中间某一元素中由于某一条件停止传递)将事件传递给最外层View 的dispatchTouchEvent(MotionEvent ev) 方法,并由该View 的dispatchTouchEvent(MotionEvent ev) 方法对事件进行分发。
Android事件分发机制-------View当触摸一个View时,首先会调用View的dispatchTouchEvent(MotionEvent event)方法,关乎着事件的分发,所以首先看看这个方法[java] view plain copy 在CODE上查看代码片派生到我的代码片public boolean dispatchTouchEvent(MotionEvent event) {// If the event should be handled by accessibility focus first.if (event.isTargetAccessibilityFocus()) {// We don't have focus or no virtual descendant has it, do not handle the event.if (!isAccessibilityFocusedViewOrHost()) {return false;}// We have focus and got the event, then use normal event dispatch.event.setTargetAccessibilityFocus(false);}boolean result = false;if (mInputEventConsistencyVerifier != null) {mInputEventConsistencyVerifier.onTouchEvent(event, 0);}final int actionMasked = event.getActionMasked();if (actionMasked == MotionEvent.ACTION_DOWN) {// Defensive cleanup for new gesturestopNestedScroll();}if (onFilterTouchEventForSecurity(event)) {//noinspection SimplifiableIfStatementListenerInfo li = mListenerInfo;if (li != null && li.mOnTouchListener != null&& (mViewFlags & ENABLED_MASK) == ENABLED&& li.mOnTouchListener.onTouch(this, event)) {result = true;}if (!result && onTouchEvent(event)) {result = true;}}if (!result && mInputEventConsistencyVerifier != null) {mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);}// Clean up after nested scrolls if this is the end of a gesture;// also cancel it if we tried an ACTION_DOWN but we didn't want the rest// of the gesture.if (actionMasked == MotionEvent.ACTION_UP ||actionMasked == MotionEvent.ACTION_CANCEL ||(actionMasked == MotionEvent.ACTION_DOWN && !result)) {stopNestedScroll();}return result;}看关键性的代码,包含了四个判断li:是ListenerInfo,点进去可以看到是各种Listener,OnFocusChangeListener,OnScrollChangeListener,OnClickListener等等。
Android 触摸事件的传递机制学习笔记一. 触摸事件的类型触摸事件对应的是 MotionEvent,主要的事件有一下三种:1. ACTION_DOWN手指的按下动作;一次ACTION_DOWN,标志着一个触摸事件的开始。
2. ACTION_UP手指离开屏幕的动作;一次 ACTION_UP,标志着一个触摸事件的结束。
3. ACTION_MOVE手指按压屏幕并且移动一定的距离;手指的轻微移动会触发一系列的 ACTION_MOVE 事件。
二. 触摸事件传递的三个阶段1. 分发 (Dispatch)事件的分发对应着dispatchTouchEvent方法,Android 系统中的所有的事件都是通过该方法来分发的。
方法原型如下:public void dispatchTouchEvent(MotionEvent event);返回值说明:true:表示触摸事件被当前视图消费,不再继续分发该事件。
super.dispatchTouchEvent:表示继续分发该事件,如果当前视图是 ViewGroup 或其子类,则由onInterceptTouchEvent决定是否拦截该事件。
2. 拦截 (Intercept)触摸事件的拦截对应着onInterceptTouchEvent方法,该方法只在 ViewGroup 或子类中存在,Activity 和 View 中没有。
方法原型:public boolean onInterceptTouchEvent(MotionEvent event);返回值说明true:表示拦截该事件,不再继续向子视图分发该事件,同时交由该视图的的onTouchEvent方法进行消费。
false | super.onInterceptTouchEvent:表示不对触摸事件进行拦截,需要继续分发给子视图进行处理。
3. 消费 (Consume)触摸事件的消费对应着onTouchEvent方法。
方法原型如下:public boolean onTouchEvent(MotionEvent event);返回值说明true:表示该视图可以处理对应的触摸事件,事件将不会向上传递给父视图。
Android中触摸事件传递分发机制触摸事件用MotionEvent表示,在Android中,一个触摸事件从产生到最终起作用,是一个很复杂的过程,但思路还是很清晰的,就是一层一层的传递,通过一个boolean值判断是否拦截或者消耗(也就是使用掉这个事件)。
下面从基础的事件产生过程开始梳理整个流程:事件的类型:一般使用手机,在屏幕上的操作就是点击或滑动,所以一般触摸事件分为两类:•点击事件:ACTION_DOWN–>ACTION_UP•滑动事件:ACTION_DOWN–>ACTION_MOVE–>ACTION_MOVE … … –>ACTION_UP可以看到,事件的开始都是ACTION_DOWN,结束是ACTION_UP。
滑动事件相比点击事件,多了n个ACTION_MOVE事件,也就是滑动过程中手指与屏幕的交互,其他就没什么区别了。
事件的传递过程:在Android中,Activity作为界面显示的基础,通常用来接收触摸事件,然后分发给界面中的视图控件。
当一个触摸事件产生时,最先传递给当前Activity,然后由Activity内部的Window将事件传递给DecorView(也就是当前屏幕显示的界面的底层容器)接下来就是在开发者编写的ViewGroup和View中传递了,所以整理下事件传递过程如下图:从图中可以看到,由于DecorView继承自FrameLayout,所以它是一个ViewGroup,ContentView也是一个ViewGroup,因此,整个传递过程可以简化为三个步骤:Activity—->ViewGroup…—->View也就是从Activity传递到ViewGroup,再经过n步的ViewGroup 之间传递,最终传递给View。
事件传递的代码实现:将以上传递规则通过代码实现,主要涉及到以下三个方法:•dispatchTouchEvent():分发触摸事件,默认返回super.dispatchTouchEvent(ev),事件向上分发。
Android事件分发机制【注】:这篇文章中的内容都以这张图来讲解分发机制,其中A、B、C都是ViewGroup,它们的层次关系为:A为根布局,B为二级子布局,C为三级子布局,其中C布局中包含一个Button按钮,即A包含B,B包含C,C包含Button。
好了,废话少说。
先来讲下今天的三位主角吧。
1、dispatchTouchEvent - 分发事件,默认为false。
true:取消事件,不继续向下分发,false:向下分发事件2、onInterceptTouchEvent - 拦截事件,默认为false。
true:拦截事件,自身的onTouchEvent()方法消费,false:事件继续向下传递3、onTouchEvent - 处理事件,默认为false,true:消费事件,false:不消费事件,向上层传递让上层处理。
【注】如果发生了拦截,那么如果该层不处理则会继续向上传递,让上层处理。
如果过程中没有发生处理,则事件分发到底层后将一直向上层传递至Activity,在Activity的onTouchEvent()中处理。
【注】如果在设置了setOnClickListener(…)的View 或Viewgroup中,返回true则消费事件,会触发onClick事件,如果返回false,则不会触发onClick事件这里借用网上的两张图片来增加理解:1、在没有做任何处理,也即默认情况下,触摸屏幕发生的一系列事件分发过程:如果DOWN事件没有被消费,则后续的MOVE/UP事件将不会传递过来,直接在Activity层处理2、如果子View消费了事件,则事件的分发过程为:上面这三个方法就是负责Android中当用户触摸屏幕时事件的分发与处理。
在Android中,事件的分发是遵循这样一套机制的:当用户触摸到屏幕时,也就是触摸到Activity界面,当Activity中的dispatchTouchEvent()方法允许分发时,这时这个触摸事件就会先出现在根布局这个ViewGroup中,然后再向里层的ViewGroup或View传递,也就是Activity->RootView->子ViewGroup->…..->View。
android事件分发理解Android事件分发是指在Android系统中,当用户触摸屏幕或执行其他操作时,系统如何将这些事件传递给应用程序的过程。
事件分发涉及多个层级,包括Activity、ViewGroup和View。
首先,事件从顶级的Activity开始,通过Activity的dispatchTouchEvent()方法进行处理。
该方法会将事件传递给当前显示的根布局ViewGroup。
接下来,ViewGroup会调用自己的dispatchTouchEvent()方法,该方法会遍历它的所有子View,并依次调用它们的dispatchTouchEvent()方法。
这个过程是递归的,直到事件传递到最底层的View。
在View的dispatchTouchEvent()方法中,会先判断事件的类型(如触摸、滑动、点击等),然后根据事件类型调用对应的回调方法(如onTouchEvent()、onScroll()、onClick()等)来处理事件。
在事件的处理过程中,每个View都有机会消费事件,即决定是否处理该事件。
如果View消费了事件,那么事件将不再向下传递给其他View。
如果View不消费事件,那么事件将继续向上传递给父View,直到被消费或传递到顶级的Activity。
此外,Android还提供了事件拦截的机制,即通过重写ViewGroup的onInterceptTouchEvent()方法来拦截事件。
当某个ViewGroup拦截了事件后,该事件将直接传递给该ViewGroup的onTouchEvent()方法进行处理,而不再向下传递给子View。
总结来说,Android事件分发是一个层级结构,从Activity到ViewGroup再到View,通过dispatchTouchEvent()方法和onTouchEvent()等回调方法来传递和处理事件。
每个View都有机会消费事件,而ViewGroup还可以拦截事件。
Android事件传递机制Android事件传递机制AndroidonInterceptTouchEvenonTouchEvent事件处理dispatchTouchEventAndroid中dispatchTouchEvent,onInterceptTouchEvent, onTouchEvent的理解android中的事件类型分为按键事件和屏幕触摸事件,Touch事件是屏幕触摸事件的基础事件,有必要对它进⾏深⼊的了解。
⼀个最简单的屏幕触摸动作触发了⼀系列Touch事件:ACTION_DOWN->ACTION_MOVE->ACTION_MOVE->ACTION_MOVE...->ACTION_MOVE->ACTION_UPandroid的事件处理分为3步。
1)public booleandispatchTouchEvent(MotionEvent ev) 这个⽅法⽤来分发TouchEvent2)public boolean onInterceptTouchEvent(MotionEvent ev) 这个⽅法⽤来拦截TouchEvent 3)public boolean onTouchEvent(MotionEvent ev) 这个⽅法⽤来处理TouchEvent假设当前Activity 布局如下:dispatchTouchEvent事件分发当TouchEvent发⽣时,⾸先Activity将TouchEvent传递给最顶层的View, TouchEvent最先到达最顶层 view 的 dispatchTouchEvent 。
然后由 dispatchTouchEvent ⽅法进⾏分发,如果dispatchTouchEvent返回true ,则交给这个view的onTouchEvent处理,如果dispatchTouchEvent返回 false ,则交给这个 view 的 onInterceptTouchEvent⽅法来决定是否要拦截这个事件,如果onInterceptTouchEvent返回 true ,也就是拦截掉了,则交给它的 onTouchEvent 来处理,如果onInterceptTouchEvent返回 false ,那么就传递给⼦ view,由⼦ view 的dispatchTouchEvent 再来开始这个事件的分发。
本文由我司收集整编,推荐下载,如有疑问,请与我司联系深入聊聊Android 事件分发机制2017/02/09 38100 在Android 开发的过程中,自定义控件一直是我们绕不开的话题。
而在这个话题中事件分发机制也是其中的重点和疑点,特别是当我们处理控件嵌套滑动事件时,正确的处理各个控件间事件分发拦截状态,可以实现更炫酷的控件动画效果。
一、事件分发机制介绍关于Android 事件分发,我们主要分ViewGroup 和View两个事件处理部分进行介绍,主要研究在处理事件过程中关注最多的三个方法dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent,在ViewGroup 和View 对三个方法的支持如下图所示:在Android 中,当用户触摸界面时系统会把产生一系列的MotionEvent,通过ViewGroup 的dispatchTouchEvent 方法开始向下分发事件,在dispatchTouchEvent方法中,会调用onInterceptTouchEvent 方法,如果该方法返回true,表明当前控件拦截了该事件,此后事件交由该控件处理并不再调用该控件的onInterceptTouchEvent 方法。
最后交由该控件的onTouchEvent 方法对事件进行处理。
如果当前控件在onInterceptTouchEvent 方法中返回false,表示不拦截该控件,之后交由其子控件进行判断是否对事件进行拦截处理。
可以用如下伪代码来对其进行处理:public boolean dispatchTouchEvent(MotionEvent event) { boolean consume = false; if (onInterceptTouchEvent(event)) { consume = onTouchEvent(event); } else { consume = child.dispatchTouchEvent(event); } return consume; }先说结论再细分析:事件是由其父视图向子视图传递,如图为A- B- C 如果当前控件需要拦截该事件,则在onInterceptTouchEvent 方法中返回true,但真正决定是否处理事件是在onTouchEvent 方法中,也就是说如果此时onTouchEvent 方法返回了false,则此控件也表示不处理该事件,交由父控件的onTouchEvent 方法来判断处理。
Android进阶——Android事件分发机制之dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent 前言Android事件分发机制可以说是我们Android工程师面试题中的必考题,弄懂它的原理是我们避不开的任务,所以长痛不如短痛,花点时间干掉他,废话不多说,开车啦Android事件分发机制的简介Android事件分发机制的发生在View与View之间或者ViewGroup与View之间具有镶嵌的视图上,而且视图上必须为点击可用。
当一个点击事件产生后,它的传递过程遵循如下顺序:Activity->Window->View,即事件先传递给Activity,再到Window,再到顶级View,才开始我们的事件分发Android事件分发机制的相关概念Android事件分发机制主要由三个重要的方法共同完成的dispatchTouchEvent:用于进行点击事件的分发onInterceptTouchEvent:用于进行点击事件的拦截onTouchEvent:用于处理点击事件这里需要注意的是View中是没有onInterceptTouchEvent()方法的Android事件分发机制的分发例子这里以两个ViewGroup嵌套View来演示,下面是演示图一、MyView继承View并覆写其三个构造方法,覆写dispatchTouchEvent和onTouchEvent,前面已经说了View是没有onInterceptTouchEvent方法的public class MyView extends View {public MyView(Context context) {super(context);}public MyView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);}public MyView(Context context, AttributeSet attrs) {super(context, attrs);}@Overridepublic boolean dispatchTouchEvent(MotionEvent event) {System.out.println("MyView dispatchTouchEvent");return super.dispatchTouchEvent(event);}@Overridepublic boolean onTouchEvent(MotionEvent event) {System.out.println("MyView onTouchEvent");return super.onTouchEvent(event);}}二、MyViewGroup01和MyViewGroup02MyViewGroup01和MyViewGroup02是一样的代码,这里以01为例,继承ViewGroup并覆写其三个构造方法,覆写dispatchTouchEvent和onTouchEvent和onInterceptTouchEvent方法public class MyViewGroup01 extends LinearLayout {public MyViewGroup01(Context context) {super(context);}public MyViewGroup01(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr);}public MyViewGroup01(Context context, AttributeSet attrs) {super(context, attrs);}@Overridepublic boolean dispatchTouchEvent(MotionEvent ev) {System.out.println("MyViewGroup01 dispatchTouchEvent");return super.dispatchTouchEvent(ev);}@Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {System.out.println("MyViewGroup01 onInterceptTouchEvent");return super.onInterceptTouchEvent(ev);}@Overridepublic boolean onTouchEvent(MotionEvent event) {System.out.println("MyViewGroup01 onTouchEvent");return super.onTouchEvent(event);}}三、MyView和MyViewGroup布局文件这里以ViewGroup和Group嵌套,由上面可以知道事件最后分配到布局的顶级View,这里的顶级View是MyViewGroup02,然后开始事件的传递<?xml version="1.0" encoding="utf-8"?><com.handsome.boke2.TouchEvent.MyViewGroup02xmlns:android="/apk/res/android"android:layout_width="200dp"android:layout_height="200dp"android:background="#0f0"><com.handsome.boke2.TouchEvent.MyViewGroup01android:layout_width="100dp"android:layout_height="100dp"android:background="#f00"><com.handsome.boke2.TouchEvent.MyViewandroid:layout_width="50dp"android:layout_height="50dp"android:background="#00f" /></com.handsome.boke2.TouchEvent.MyViewGroup01></com.handsome.boke2.TouchEvent.MyViewGroup02>四、分析事件传递点击MyView(即蓝色部分):其事件会从顶级View(MyViewGroup02)往下分发,而事件的分发过程中分为两步骤分发过程处理过程其正常的分发事件结果为//分发过程MyViewGroup02 dispatchTouchEventMyViewGroup02 onInterceptTouchEventMyViewGroup01 dispatchTouchEventMyViewGroup01 onInterceptTouchEventMyView dispatchTouchEvent//处理过程MyView onTouchEventMyViewGroup01 onTouchEventMyViewGroup02 onTouchEvent1、dispatchTouchEvent(分发事件)如果在MyViewGroup01的dispatchTouchEvent方法中返回true,表示需要在MyViewGroup01消费了整个事件,即不会再分发,也不会再处理。
dispatchTouchEvent方法中返回true的打印信息//分发过程MyViewGroup02 dispatchTouchEventMyViewGroup02 onInterceptTouchEventMyViewGroup01 dispatchTouchEvent如果在MyViewGroup01的dispatchTouchEvent方法中返回false,表示在MyViewGroup01点击事件在本层不再继续进行分发,并交由上层控件的onTouchEvent方法进行消费。
dispatchTouchEvent方法中返回false的打印信息//分发过程MyViewGroup02 dispatchTouchEventMyViewGroup02 onInterceptTouchEventMyViewGroup01 dispatchTouchEvent//处理过程MyViewGroup02 onTouchEvent2、onInterceptTouchEvent(拦截事件)如果在MyViewGroup01的onInterceptTouchEvent方法中返回true,表示需要在MyViewGroup01拦截这个点击事件,不再继续往下分发,即MyView不再执行dispatchTouchEvent方法。
但是只是分发结束了而已,接着开始处理事件。
下面是onInterceptTouchEvent方法中返回true的打印信息//分发过程MyViewGroup02 dispatchTouchEventMyViewGroup02 onInterceptTouchEventMyViewGroup01 dispatchTouchEventMyViewGroup01 onInterceptTouchEvent//处理过程MyViewGroup01 onTouchEventMyViewGroup02 onTouchEvent如果在MyViewGroup01的onInterceptTouchEvent方法中返回false,表示需要在MyViewGroup01不会拦截这个点击事件,继续往下分发。
下面是onInterceptTouchEvent方法中返回false的打印信息//分发过程MyViewGroup02 dispatchTouchEventMyViewGroup02 onInterceptTouchEventMyViewGroup01 dispatchTouchEventMyViewGroup01 onInterceptTouchEventMyView dispatchTouchEvent//处理过程MyView onTouchEventMyViewGroup01 onTouchEventMyViewGroup02 onTouchEvent3、onTouchEvent(消费事件)如果MyViewGroup01的onTouchEvent方法中返回true,表示MyViewGroup01可以将该事件直接消费掉了,即分发结束后,处理事件的时候,直接处理到MyViewGroup01就可以结束了。