Android焦点事件分发与传递机制

合集下载

android 事件传递原理

android 事件传递原理

android 事件传递原理Android是当前最流行的移动操作系统,它的事件传递机制是安卓开发中必须了解的一个问题。

本文将带您从简单到复杂的三个方面,逐步解析安卓事件传递的原理。

一、事件类型首先,我们需要知道Android事件的三大类型:1. 触摸事件:通过手指在屏幕上进行滑动、点击等手势操作触发。

2. 按键事件:用户在设备上的按键输入,如键盘、物理键等。

3. 轨迹球事件:主要针对轨迹球设备,但是由于这种设备很少被使用,所以这里不再深入讲解。

二、事件传递流程在了解了事件类型后,我们可以探讨一下事件传递的具体流程。

每一个事件都是通过ViewGroup或者View的dispatchTouchEvent()方法进行传递的。

我们可以将事件的传递过程抽象为TouchTarget链表。

当一个事件发生后,它会从Activity开始一层层向下传递,当找到能够处理该事件的View或ViewGroup时,则会调用其onTouchEvent()方法完成相应操作。

如果从顶层的ViewGroup开始寻找,当它的dispatchTouchEvent()方法返回true时,则整个事件处理结束。

如果返回false,则事件继续向下传递给下一个ViewGroup或View,直到找到可以处理这个事件的View为止。

由此可见,对于同一个事件,ViewGroup和父子View的处理有时是相互影响的,需要通过继承ViewGroup或者View,重写dispatchTouchEvent()和onTouchEvent()方法来控制事件传递的方式。

三、事件分发机制实际上,在ViewGroup中,事件传递机制涉及到的方法有三个:1. dispatchTouchEvent():负责分发事件。

2. onInterceptTouchEvent():拦截事件,阻止向下分发。

3. onTouchEvent():接收分发下来的事件。

其中,事件分发有三个阶段:1. 捕获阶段:事件从Activity传递到最外层的ViewGroup。

Android中的事件传递与事件处理机制

Android中的事件传递与事件处理机制

Android中的事件传递与事件处理机制概述当Android系统捕获到用户的各种输入事件后,如何准确地传递给真正需要这个事件的控件呢?Android系统给我们提供了一整套完善的事件传递、处理机制,来帮助开发者完成准确的事件传递与处理。

预备知识1.Android应用中Activity的视图层级结构2.每个Activity都是通过PhoneWindow来呈现View的,PhoneWindow中最顶层View是mDecor(DecorView的对象),当我们在Activity中调用setContentView()设置布局时会调用PhoneWindow的setContentView()方法生成DecorView对象mDecor。

mDecor只有一个子元素为LinearLayout,而LinearLayout下包含两个FrameLayout,上面那个FrameLayout为标题栏显示界面,包含一个id为android.R.id.title的TextView,而下面那个FrameLayout的id为android.R.id.content,我们通过setContentView()设置进来的布局界面就会放在这个FrameLayout中。

mDecor的视图层级结构如下图所示:mDecor的视图层级结构因此,我们可以通过((ViewGroup)getWindow().getDecorView().findViewById(an droid.R.id.content)).getChildAt(0)这种方式获取到Activity所设置的View。

3.MotionEvent事件4.在手指接触屏幕后所产生的一系列事件中,典型的事件类型有如下几种:ACTION_DOWN ----- 手指刚接触屏幕ACTION_MOVE ----- 手指在屏幕上移动ACTION_UP ----- 手指从屏幕上松开的一瞬间正常情况下,一次手指触碰屏幕的行为会触发一系列触摸事件,考虑如下几种情况:点击屏幕后立即松开,事件顺序为ACTION_DOWN -> ACTION_UP点击屏幕后滑动一会再松开,事件顺序为ACTION_DOWN -> ACTION_MOVE ->...-> ACTION_MOVE -> ACTION_UP 上面两种情况是典型的事件序列,同时通过MotionEvent对象我们可以得到点击事件发生的x和y坐标。

Android 事件处理机制

Android 事件处理机制

Android 事件处理机制Android 作为一款主流的移动操作系统,拥有强大的事件处理机制,使得开发者可以方便地对用户的操作进行响应和处理。

本文将介绍Android的事件处理机制及其相关的内容。

一、概述Android事件处理机制主要用于检测和响应用户在界面上的各种操作,包括点击、滑动、长按等。

通过灵活运用Android事件处理机制,开发者可以实现丰富多样的用户交互效果,提升应用的用户体验。

二、事件传递1. 事件传递的核心概念- 事件传递分为三个阶段:事件分发、事件拦截、事件处理。

- 事件的传递是从上至下的过程,即从Activity到ViewGroup,再到最终的View。

2. 事件分发- 事件首先会被分发给当前界面的顶层View的dispatchTouchEvent()方法进行处理。

- 顶层View会根据具体的触摸事件类型(DOWN、MOVE、UP、CANCEL)进行相应的处理。

3. 事件拦截- 如果顶层View在处理事件后,认为自己不能完全处理该事件,则会将事件交给子View处理,通过调用子View的dispatchTouchEvent()方法传递事件给子View。

- 子View可以通过重写onInterceptTouchEvent()方法来决定是否拦截事件。

4. 事件处理- 最终,事件会传递到具体的View上,并通过重写onTouchEvent()方法来实现事件的处理。

- View可以根据具体的事件类型(点击、滑动、长按等)执行相应的操作。

三、事件分发机制1. 事件分发的层级关系- Android中的事件分发机制是基于层级关系的,即不同的ViewGroup和View之间存在不同的事件分发机制。

- ViewGroup和View都重写了dispatchTouchEvent()方法,用于对事件进行分发。

2. ViewGroup中的事件分发- ViewGroup会根据具体的事件类型,将事件传递给自己的子View。

Android事件分发机制

Android事件分发机制

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 事件分发机制详解:史上最全面、最易懂Android 事件分发机制是每个Android 开发者必须了解的基础知识网上有大量关于Android 事件分发机制的文章,但存在一些问题:内容不全、思路不清晰、无源码分析、简单问题复杂化等等今天,我将全面总结Android 的事件分发机制,我能保证这是市面上的最全面、最清晰、最易懂的本文秉着“结论先行、详细分析在后”的原则,即先让大家感性认识,再通过理性分析从而理解问题;因此,请各位读者先记住结论,再往下继续看分析;1. 基础认知1.1 事件分发的对象是谁?答:事件当用户触摸屏幕时(View 或ViewGroup 派生的控件),将产生点击事件(Touch 事件)。

Touch 事件相关细节(发生触摸的位置、时间、历史记录、手势动作等)被封装成MotionEvent 对象主要发生的Touch 事件有如下四种:MotionEvent.ACTION_DOWN:按下View(所有事件的开始)MotionEvent.ACTION_MOVE:滑动View MotionEvent.ACTION_CANCEL:非人为原因结束本次事件MotionEvent.ACTION_UP:抬起View(与DOWN 对应)事件列:从手指接触屏幕至手指离开屏幕,这个过程产生的一系列事件任何事件列都是以DOWN 事件开始,UP 事件结束,中间有无数的MOVE 事件,如下图:即当一个MotionEvent 产生后,系统需要把这个事件传递给一个具体的View 去处理,1.2 事件分发的本质答:将点击事件(MotionEvent)向某个View 进行传递并最终得到处理即当一个点击事件发生后,系统需要将这个事件传递给一个具体的View 去处理。

这个事件传递的过程就是分发过程。

1.3 事件在哪些对象之间进行传递?答:Activity、ViewGroup、View。

图解Android事件分发机制

图解Android事件分发机制

图解Android事件分发机制在Android开发中,事件分发机制是一块Android比较重要的知识体系,了解并熟悉整套的分发机制有助于更好的分析各种点击滑动失效问题,更好去扩展控件的事件功能和开发自定义控件,同时事件分发机制也是Android面试必问考点之一,如果你能把下面的一些事件分发图当场画出来肯定加分不少。

废话不多说,总结一句:事件分发机制很重要。

作者:佚名来源:安卓开发精选|2016-12-08 10:19收藏分享在Android开发中,事件分发机制是一块Android比较重要的知识体系,了解并熟悉整套的分发机制有助于更好的分析各种点击滑动失效问题,更好去扩展控件的事件功能和开发自定义控件,同时事件分发机制也是Android面试必问考点之一,如果你能把下面的一些事件分发图当场画出来肯定加分不少。

废话不多说,总结一句:事件分发机制很重要。

Android 事件分发流关于Android 事件分发机制网上的博文很多,但是很多都是写个Demo然后贴一下输出的Log或者拿源码分析,然后一堆的注释和说明,如果用心的去看肯定是收获不少但是确实很难把整个流程说清和记住。

曾经也是拼命想记住整个流程,但是一段时间又忘了,最后觉得分析这种问题和事件流的走向,一张图来解释和说明会清晰很多,下面我根据画的一张事件分发流程图,说明的事件从用户点击之后,在不同函数不同返回值的情况的最终走向。

图 1.注:∙仔细看的话,图分为3层,从上往下依次是Activity、ViewGroup、View ∙事件从左上角那个白色箭头开始,由Activity的dispatchTouchEvent做分发∙箭头的上面字代表方法返回值,(return true、return false、return super.xxxxx(),super 的意思是调用父类实现。

∙dispatchTouchEvent和onTouchEvent的框里有个【true—->消费】的字,表示的意思是如果方法返回true,那么代表事件就此消费,不会继续往别的地方传了,事件终止。

android中的事件传递和处理机制

android中的事件传递和处理机制

android中的事件传递和处理机制⼀直以来,都被android中的事件传递和处理机制深深的困扰!今天特意来好好的探讨⼀下。

现在的感觉是,只要你理解到位,其实事件的传递和处理机制并没有想象中的那么难。

总之,不要⾃⼰打击⾃⼰,要相信⾃⼰能掌握这块知识。

好了,下⾯是我今天的收获,希望也能对你有⼀点帮助。

⼀、拟⼈化来理解android中的事件机制其实android中的事件传递与处理机制跟我们⽣活中的事件处理是⼀样的。

这⾥有⼀个⽣活中的例⼦,很能说明这个问题。

阐述如下:你是⼀个公司的员⼯,你的上头有⼀个主管,主管上头呢还有⼀个经理。

为了简单,你们这个团队就有这三个⼈。

那么如果上头安排⼀件事下来要处理,流程是怎样的呢?显然应该是由你的经理将这件事安排给你的主管来处理,你的主管再将这件事安排给你来处理。

等你把这件事办好了,你就应该给你的主管报告,再由你的主管来向你的经理报告。

显然,你的主管和经理也有处理这件事的权限,如果他们觉得事情很复杂,你办不了,或者他们⽐较照顾下级,可能就⾃⼰把这件事给办了,这个时候这件事就不会再传递给下⼀级来处理了。

这个事件处理的过程,是不是太容易理解了!其实android中的事件处理流程就是跟⽣活中的事件处理是⼀样的。

⽐如你在ViewGroupA中嵌套了⼀个VewiGroupB,然后⼜在ViewGroupB中嵌套了⼀个MyView。

那么⼀个触摸事件传递过来,会发⽣什么情况呢?类⽐上⾯的公司员⼯的处理事件,显然会发⽣下⾯的过程:触摸事件传递过来后,ViewGroupA⼀看⾃⼰⾥⾯还有⼀个员⼯可以利⽤,就是ViewGroupB,那不⽤⽩不⽤,就会把这个事件传递给ViewGroupB,告诉他,你给我把这个事件处理了!ViewGroupB呢⼀看,我不怕,我⾥⾯也有⼀个员⼯就是MyView,它得给我⼲活,于是⼜会把这个事件传递给MyView,让它来处理。

MyView⼀看,没办法啊,我⼿底下没有员⼯了,那怎么办,我只能⾃⼰处理了(前提是它有处理这个事件的能⼒),所以就把这个触摸事件给处理了。

Android焦点事件分发与传递机制

Android焦点事件分发与传递机制

Android焦点事件分发与传递机制下面我们就从源码来带大家进行安卓TV焦点事件的传递这里先给出Android系统View的绘制流程:依次执行View类里面的如下三个方法:measure(int ,int) :测量View的大小layout(int ,int ,int ,int) :设置子View的位置draw(Canvas) :绘制View内容到Canvas画布上ViewRootImpl的主要作用如下(此处不多讲,如有意图,看源码):A:链接WindowManager和DecorView的纽带,更广一点可以说是Window和View之间的纽带。

B:完成View的绘制过程,包括measure、layout、draw过程。

C:向DecorView分发收到的用户发起的event事件,如按键,触屏等事件。

ViewRootImpl不再多余叙述,进入正题:Android焦点分发的主要方法以及拦截方法的讲解。

在RootViewImpl中的函数通道是各种策略(InputStage)的组合,各策略负责的任务不同,如SyntheticInputStage、ViewPostImeInputStage、NativePostImeInputStage等等,这些策略以链表结构结构起来,当一个策略者没有消费事件时,就传递个下一个策略者。

其中触摸和按键事件由ViewPostImeInputStage处理。

@Overrideprotected int onProcess(QueuedInputEvent q) {if (q.mEvent instanceof KeyEvent) {return processKeyEvent(q);//如果是按键事件走此处,处理按键和焦点问题了} else {final int source = q.mEvent.getSource();if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {return processPointerEvent(q);//如果是触摸事件走此处} else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {return processTrackballEvent(q);} else {return processGenericMotionEvent(q);}}}processKeyEvent(QueuedInputEvent q)源码如下:@Overrideprotected void onDeliverToNext(QueuedInputEvent q) {if (mUnbufferedInputDispatch&& q.mEvent instanceof MotionEvent&& ((MotionEvent)q.mEvent).isTouchEvent()&& isTerminalInputEvent(q.mEvent)) {mUnbufferedInputDispatch = false;scheduleConsumeBatchedInput();}super.onDeliverToNext(q);}private int processKeyEvent(QueuedInputEvent q) {final KeyEvent event = (KeyEvent)q.mEvent;// Deliver the key to the view hierarchy.if (mView.dispatchKeyEvent(event)) {return FINISH_HANDLED;}if (shouldDropInputEvent(q)) {return FINISH_NOT_HANDLED;}// If the Control modifier is held, try to interpret the key as a shortcut. if (event.getAction() == KeyEvent.ACTION_DOWN&& event.isCtrlPressed()&& event.getRepeatCount() == 0&& !KeyEvent.isModifierKey(event.getKeyCode())) { if (mView.dispatchKeyShortcutEvent(event)) {return FINISH_HANDLED;}if (shouldDropInputEvent(q)) {return FINISH_NOT_HANDLED;}}// Apply the fallback event policy.if (mFallbackEventHandler.dispatchKeyEvent(event)) {return FINISH_HANDLED;}if (shouldDropInputEvent(q)) {return FINISH_NOT_HANDLED;}// Handle automatic focus changes.if (event.getAction() == KeyEvent.ACTION_DOWN) {int direction = 0;switch (event.getKeyCode()) {case KeyEvent.KEYCODE_DPAD_LEFT:if (event.hasNoModifiers()) {direction = View.FOCUS_LEFT;}break;case KeyEvent.KEYCODE_DPAD_RIGHT:if (event.hasNoModifiers()) {direction = View.FOCUS_RIGHT;}break;case KeyEvent.KEYCODE_DPAD_UP:if (event.hasNoModifiers()) {direction = View.FOCUS_UP;}break;case KeyEvent.KEYCODE_DPAD_DOWN:if (event.hasNoModifiers()) {direction = View.FOCUS_DOWN;}break;case KeyEvent.KEYCODE_TAB:if (event.hasNoModifiers()) {direction = View.FOCUS_FORW ARD;} else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) {direction = View.FOCUS_BACKWARD;}break;}if (direction != 0) {View focused = mView.findFocus();if (focused != null) {View v = focused.focusSearch(direction);if (v != null && v != focused) {// do the math the get the interesting rect// of previous focused into the coord system of// newly focused viewfocused.getFocusedRect(mTempRect);if (mView instanceof ViewGroup) {((ViewGroup)mView).offsetDescendantRectToMyCoords(focused, mTempRect);((ViewGroup) mView).offsetRectIntoDescendantCoords(v, mTempRect);}if (v.requestFocus(direction, mTempRect)) {playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction));return FINISH_HANDLED;}}// Give the focused view a last chance to handle the dpad key.if (mView.dispatchUnhandledMove(focused, direction)) {return FINISH_HANDLED;}} else {// find the best view to give focus to in this non-touch-mode with no-focusView v = focusSearch(null, direction);if (v != null && v.requestFocus(direction)) {return FINISH_HANDLED;}}}}return FORW ARD;}进入源码讲解:(1) 首先由dispatchKeyEvent进行焦点的分发如果dispatchKeyEvent方法返回true,那么下面的焦点查找步骤就不会继续了。

【IT专家】深入聊聊Android事件分发机制

【IT专家】深入聊聊Android事件分发机制

本文由我司收集整编,推荐下载,如有疑问,请与我司联系深入聊聊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开发培训课程之事件分发机制

因为android的界面可能是由多个视图层层嵌套构成,当一个触摸事件发生时,系统需要把这个事件传递给一个具体的View,由它来完成处理。从事件发生,到传递给具体的View去完成,这个传递的过程就是View 事件分发。
2、相关
此时我们引入触摸事件,简单来说就是是触摸屏幕产生的动作事件,比如常见的手指按下,移动,抬起等等,android为我们提供了一个专门的MotionEvent类,它包含了发生的动作事件以及相关坐标信息,利用MotionEvent,我们可以处理很多与动作相关的工作。这里的View其实指的是View以及ViewGroup,我们知道View是android中所有控件的基类,而ViewGroup翻译为视图组,它是继承自View的,可以包含子控件。我们在接下来的讨论中,会把ViewGroup和View分开讨论。
android系统经过近年不断更新和发展,成为当下移动操作系统的卫冕之王。未来行业内将会需要大量android开发技术人员。于此华清创客学院在线android开发培训课程陆续上线。帮助更多想要在android开发领域长期立足发展的年轻人,为市场需求和人才培训做好传送和递接的角色。

3、详解
事件分发过程涉及要素有三个方面,包括:dispatchTouchEvent 用于事件分发;onInterceptTouchEvent 用于拦截事件;onTouchEvent 用于处理事件。
上面三个方法之间的关系大概如下,当事件传递到某个View时,先执行dispatchTouchEvent方法进行事件分发,在这个方法内会调用方法onInterceptTouchEvent来决定是否拦截,如果返回true表示拦截,则调用onTouchEvent进行事件处理,否则继续往下传递,执行子View的dispatchTouchEvent。需要注意一点,View没有onInterceptTouchEvent方法,一旦有事件传递给它,那么它的onTouchEvent方法就会被调用。ViewGroup默认不拦截任何事件,因为从源码中可以看到ViewGroup的onInterceptTouchEvent方法默认返回false.我们知道,四大组件中,Activity通常提供界面用于交互,我们会通过setContentView来设置界面布局,一般如果我们不希望布局顶部出现一个标题栏,我们可能会调用requestWindowFeature(Window.FEATURE_NO_TITLE);方法,这里我们简单了解一下android的界面架构。

android事件分发机制 简单完整总结

android事件分发机制 简单完整总结

android事件分发机制简单完整总结
Android事件分发机制是指在Android系统中,如何将触摸事件或其他类型的事件传递给合适的View进行处理的过程。

它主要包括三个层级:顶层的Activity/Window、中间层的ViewGroup、底层的View。

简单来说,Android的事件分发机制遵循以下步骤:
1. 用户在屏幕上触发一个事件,比如点击、滑动等等。

2. 事件首先通过Activity的dispatchTouchEvent()方法进行处理。

3. Activity会将事件交给顶层的Window进行处理,在Window内部会创建一个DecorView来接收触摸事件。

4. DecorView会将事件传递给根布局ViewGroup进行处理。

5. 根布局ViewGroup会递归遍历所有的子View,通过调用每个子View的dispatchTouchEvent()方法,依次传递触摸事件。

6. 如果某个子View消费了事件(返回true),那么事件传递就终止,其它子View将不再收到事件。

7. 如果没有子View能够消费事件,或者所有子View都返回false,那么事件会继续向上传递给父ViewGroup。

8. 如果根布局ViewGroup也无法消费事件(所有子View都返回false),那么最终事件会传递给Activity的onTouchEvent()方法进行处理。

总结起来,Android的事件分发机制是一个从顶层到底层的逐层传递的过程,每个层级都有机会处理事件,通过返回值来判断是否消费
事件。

这样设计可以灵活地处理各种不同的事件,同时将事件分发和处理的责任分担给了不同的组件,提高了系统的灵活性和性能。

Android事件分发机制全面解析

Android事件分发机制全面解析

Android事件分发机制全⾯解析⽬录事件分发机制ViewGroup.dispatchTouchEvent 源码分析View.dispatchTouchEvent 和 View.onTouchEvent 源码分析事件分发机制事件分发机制的两个阶段:分发:事件从⽗视图往⼦视图分发,被拦截后不再传递,进⼊回溯阶段回溯:事件从⼦视图往⽗视图回溯,被消费后不再回溯关键⽅法:ViewGroup.dispatchTouchEvent 往⼦视图分发事件ViewGroup.onInterceptTouchEvent 返回 true 表⽰拦截分发事件,不再传递,进⼊当前视图 onTouchEvent View.dispatchTouchEvent 默认事件分发,调⽤ onTouchEventView.onTouchEvent 通常重载此⽅法处理事件,返回 true 表⽰消费事件,不再传递,返回 false 往上回溯ViewParent.requestDisallowInterceptTouchEvent(true) 可以确保事件分发到⼦视图前不被拦截假设视图层次为 A.B.C.D,事件分发回溯默认过程为:A.dispatchTouchEventB.dispatchTouchEventC.dispatchTouchEventD.dispatchTouchEventD.onTouchEventC.onTouchEventB.onTouchEventA.onTouchEvent假设 B 拦截了事件:A.dispatchTouchEventB.dispatchTouchEvent -> B.onInterceptTouchEventB.onTouchEventA.onTouchEvent假设 C.onTouchEvent 消费了事件:A.dispatchTouchEventB.dispatchTouchEventC.dispatchTouchEventD.dispatchTouchEventD.onTouchEventC.onTouchEvent事件分发机制伪代码:class Activity {fun dispatchTouchEvent(ev) {if (parent.dispatchTouchEvent(ev)) {return true}return onTouchEvent(ev)}fun onTouchEvent(ev):Boolean {...}}class ViewGroup : View {fun dispatchTouchEvent(ev) {var handled = falseif (!onInterceptTouchEvent(ev)) {handled = child.dispatchTouchEvent(ev)}return handled || super.dispatchTouchEvent(ev)}fun onInterceptTouchEvent(ev):Boolean {...}fun onTouchEvent(ev):Boolean {...}}class View {fun dispatchTouchEvent(ev) {var result = falseif (handleScrollBarDragging(ev)) {result = true}if (!result && mOnTouchListener.onTouch(ev)) {result = true}if (!result && onTouchEvent(ev)) {result = true}return result}fun onTouchEvent(ev):Boolean {...}}ViewGroup.dispatchTouchEvent 源码分析1.开始:ACTION_DOWN 事件开始⼀个新的事件序列,清除之前触摸状态2.拦截:2.1. ⾮ ACTION_DOWN 事件如果当前没有⼦视图消费事件,表⽰事件序列已被拦截2.2. 事件未被拦截且⼦视图未申请禁⽌拦截时,再通过 onInterceptTouchEvent 尝试拦截事件3.分发:如果事件未被拦截也未被取消,就遍历⼦视图分发事件,并寻找当前事件的触摸⽬标3.1. 在触摸⽬标链表中找到了可以消费当前事件的视图触摸⽬标 -> 将其标记为当前触摸⽬标,延迟到步骤4分发事件给它3.2. ⼀个不在触摸⽬标链表中的视图消费了事件 -> 将其标记为当前触摸⽬标,并设置为触摸⽬标链表表头3.3. 未找到消费当前事件的视图,但触摸⽬标链表不为空 -> 将触摸⽬标链表末端标记为当前触摸⽬标4.分发:触摸⽬标链表不为空,则遍历触摸⽬标链尝试传递事件或取消触摸⽬标(事件被拦截)5.回溯:触摸⽬标链表为空(当前没有⼦视图消耗事件序列),则将事件转发给基类 dispatchTouchEvent 处理注:触摸⽬标(ViewGourp.TouchTarget) 描述⼀个被触摸的⼦视图和它捕获的指针idspublic boolean dispatchTouchEvent(MotionEvent ev) {// 省略代码 ...boolean handled = false;if (onFilterTouchEventForSecurity(ev)) {if (actionMasked == MotionEvent.ACTION_DOWN) {// 1. `ACTION_DOWN` 事件开始⼀个新的事件序列,清除之前触摸状态 ...}// 省略代码 ...final boolean intercepted;// 2. 拦截if (actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null) {final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;if (!disallowIntercept) {// 2.2. 事件未被拦截且⼦视图未申请禁⽌拦截时,再通过 onInterceptTouchEvent 尝试拦截事件intercepted = onInterceptTouchEvent(ev);// 省略代码 ...} else {intercepted = false;}} else {// 2.1. ⾮ `ACTION_DOWN` 事件如果当前没有⼦视图消费事件,表⽰事件序列已被拦截intercepted = true;}// 省略代码 ...if (!canceled && !intercepted) {// 省略代码 ...// 3. 分发:如果事件未被拦截也未被取消,就遍历⼦视图分发事件,并寻找当前事件的触摸⽬标for (int i = childrenCount - 1; i >= 0; i--) {// 省略代码 ...newTouchTarget = getTouchTarget(child);if (newTouchTarget != null) {// 3.1. 在触摸⽬标链表中找到了可以消费当前事件的视图触摸⽬标 -> 将其标记为当前触摸⽬标,延迟到步骤4分发事件给它// 省略代码 ...break;}if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {// 省略代码 ...// 3.2. ⼀个不在触摸⽬标链表中的视图消费了事件 -> 将其标记为当前触摸⽬标,并设置为触摸⽬标链表表头newTouchTarget = addTouchTarget(child, idBitsToAssign);alreadyDispatchedToNewTouchTarget = true;break;}// 省略代码 ...}if (newTouchTarget == null && mFirstTouchTarget != null) {// 3.3. 未找到消费当前事件的视图,但触摸⽬标链表不为空 -> 将触摸⽬标链表末端标记为当前触摸⽬标newTouchTarget = mFirstTouchTarget;while (newTouchTarget.next != null) {newTouchTarget = newTouchTarget.next;}newTouchTarget.pointerIdBits |= idBitsToAssign;}// 省略代码 ...}// Dispatch to touch targets.if (mFirstTouchTarget == null) {// 5. 回溯:触摸⽬标链表为空(当前没有⼦视图消耗事件序列),则将事件转发给基类 dispatchTouchEvent 处理handled = dispatchTransformedTouchEvent(ev, canceled, null, TouchTarget.ALL_POINTER_IDS);} else {// 省略代码 ...// 4. 分发:触摸⽬标链表不为空,则遍历触摸⽬标链尝试传递事件或取消触摸⽬标(事件被拦截)TouchTarget target = mFirstTouchTarget;while (target != null) {final TouchTarget next = target.next;// 省略代码 ...if (dispatchTransformedTouchEvent(ev, cancelChild, target.child, target.pointerIdBits)) {handled = true;}// 省略代码 ...target = next;}}// 省略代码 ...}// 省略代码 ...return handled;}View.dispatchTouchEvent 和 View.onTouchEvent 源码分析滚动条消费⿏标事件OnTouchListener 消费触摸事件onTouchEvent 消费触摸事件TouchDelegate 消费触摸事件public boolean dispatchTouchEvent(MotionEvent event) {// 省略代码 ...boolean result = false;// 省略代码 ...if (onFilterTouchEventForSecurity(event)) {// 滚动条消费⿏标事件if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) {result = true;}// OnTouchListener 消费触摸事件ListenerInfo li = mListenerInfo;if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED && li.mOnTouchListener.onTouch(this, event)) { result = true;}// View默认的事件处理逻辑,事件可能在其中被设置的 TouchDelegate 消费if (!result && onTouchEvent(event)) {result = true;}}// 省略代码 ...return result;}public boolean onTouchEvent(MotionEvent event) {// 省略代码 ...if (mTouchDelegate != null) {// TouchDelegate 消费触摸事件if (mTouchDelegate.onTouchEvent(event)) {return true;}}// 省略代码 ...return false;}以上就是Android事件分发机制全⾯解析的详细内容,更多关于Android事件分发机制的资料请关注其它相关⽂章!。

android事件分发理解

android事件分发理解

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事件分发机制

Android事件分发机制前⾔事件分发的对象是点击事件。

事件分发的类型事件共有四种类型:MotionEvent.ACTION_DOWN:按下ViewMotionEvent.ACTION_UP:抬起ViewMotionEvent.ACTION_MOVE:滑动ViewMotionEvent.ACTION_CANCEL:事件意外结束事件传递的途径事件在Activity、ViewGroup、View中传递,先传到Activity再传到ViewGroup最后传到ViewGroup是⼀组View的集合,是View的⼦类,但也是⼀个View。

相关⽅法dispatchTouchEvent() 进⾏事件分发onTouchEvent() 处理事件在dispatchTouchEvent()内部调⽤onInterceptTouchEvent() 判断是否拦截了某个事件,只存在于ViewGroup中总体流程1. 事件从Activity发⽣后,Activity判断dispatchTouchEvent⽅法的返回值,默认情况下该⽅法内部直接调⽤ViewGroup的dispatchTouchEvent⽅法(下⼀层),如果该⽅法返回true说明事件在ViewGroup层被消费,事件分发结束(Activity的dispatchTouchEvent返回true);如果该⽅法返回false说明ViewGroup层没有消费此事件,需要Activity层进⾏处理(Activity调⽤onTouchEvent()、dispatchTouchEvent返回false)。

如果Activity. onTouchEvent()返回true说明事件在Activity的Windows边界外,事件不会被Activity下的任意组件处理,事件分发结束。

如果Activity. onTouchEvent()返回false说明事件在Activity的Window边界内,但是该事件不被处·理,事件分发结束。

Android事件传递机制

Android事件传递机制

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界面事件机制

Android界面事件机制

Android界⾯事件机制⼀. android界⾯事件分类: 1.KeyEvent 2.TouchEvent 3.TrackballEvent(现在不怎么使⽤了)⼆. android界⾯事件的触发及分发 1.事件触发的两种⽅法:扩展view的时候回调事件函数(内), 注册事件监听器(外) 2.时间分发dispatchKeyEvent:keyEvent分发,touchEvent分发 keyEvent分发:当我们点击了⼀个按钮,就会发送⼀个消息到当前上下⽂,context⼜分发到当前窗体的⼀个实例,然后windows优先发送给输⼊法窗体,然后发送给rootView, 然后⼀层⼀层最终分发给获取focus的view。

事件的处理是先处理⼜focus的view,然后⼀层⼀层往上。

touchEvent分发:当我们点击⼀个view,⽐如textview,系统就能快速定位到我们点击的view。

例如在当前窗体点击menu弹出⼀个popupwindow,第⼆次点击menu就不会触发任何事件。

因为此时的焦点已经移动到了popupwindow上⾯,但是popupwindow它是window,⽽没有继承view,所以它⾃⼰没有onkeyDown或onkey或dispatchKeyEvent事件,所以我们要为popupwindow的⼦view设置setFocusableInTouchMode(true)属性,然后给⼦view设置按键监听才能响应popupwindows窗⼝消失的事件。

最后再推荐⼀个⼩⼯具,android sdk下⾯的hierarchyviewer,这个⼯具现在已经⽤android device monitor代替了,这个⼯具可以查看当前屏幕下的布局层级关系,分析布局的合理性很有⽤ 这些都是很基础很简单的东西,在此纪录下来学习的过程。

事件分发机制和事件传递机制

事件分发机制和事件传递机制

事件分发机制和事件传递机制1. 触屏事件先传递给⽗容器的onInterceptTouchEvent⽅法(注:⾮容器没有onInterceptTouchEvent⽅法,可以把事件⽐作运货的车⼦,onInterceptTouchEvent⽐作是⼀个⼟匪关卡)return true,事件被拦截,事件直接传递给⽗容器的onTouchEvent,此次事件与⼦控件⽆关,因此onInterceptTouchEvent不会继续接收到ACTION_MOVE,ACTION_UP事件return false,事件优先传递给⼦控件处理2. ⼦控件onTouchEvent接收到ACTION_DOWN事件,return true ⼦控件消费事件,事件不向上回传,关卡没有拦截,后续每次都要从关卡过,即⽗容器onInterceptTouchEvent会继续接收到ACTION_MOVE,ACTION_UP事件,⼦控件的onTouchEvent也会陆续接收到ACTION_MOVE,ACTION_UP事件return false ⼦控件不处理,事件向上回传⽗控件,第⼀次来关卡虽然没有拦截,但是⼦控件第⼀次就声明不处理,下次车⼦也不⽤再来关卡了,即⽗容器onInterceptTouchEvent不会继续接收到ACTION_MOVE,ACTION_UP事件,⼦控件的onTouchEvent更不可能接收到ACTION_MOVE,ACTION_UP事件3. ⽗控件onTouchEvent接收到ACTION_DOWN事件后return true ⽗控件消费事件,不再向上传递,onTouchEvent会陆续接收到ACTION_MOVE,ACTION_UP事件,事件不会向下传递,也就不关onInterceptTouchEvent什么事了return false ⽗控件不处理,事件向上回传⽗控件,onTouchEvent不会接收到ACTION_MOVE,ACTION_UP事件,这种情况是全部默认,即⽗容器不拦截,也不处理,⾃控件也不处理,事件传了三次就⾛了,也不会回来了。

android事件分发理解

android事件分发理解

android事件分发理解【原创版】目录1.事件分发的概念与意义2.Android 事件分发的流程3.事件分发中的关键角色4.事件分发的实际应用案例正文1.事件分发的概念与意义在 Android 系统中,用户与应用程序的交互通常通过触摸屏幕上的视图元素(如按钮、文本框等)来实现。

然而,在复杂的用户界面中,可能会有多个视图元素重叠在一起,用户触摸的位置可能落在多个视图元素的范围内。

这就引发了一个问题:哪个视图元素应该响应这个触摸事件?为了解决这个问题,Android 引入了事件分发机制。

事件分发是指在 Android 系统中,根据用户触摸事件的发生位置,将事件分配给对应的视图元素进行处理的过程。

这个过程从 Activity 开始,通过 ViewGroup 和 View 等多个组件,最终使得事件被消费或者传递给其他组件。

2.Android 事件分发的流程Android 事件分发的流程可以概括为以下几个步骤:(1)Activity 接收事件:首先,用户触摸事件会传递给 Activity。

Activity 是一个应用程序的入口,也是系统与用户交互的媒介。

Activity 会调用 Window 对象的 dispatchTouchEvent 方法进行事件分发。

(2)Window 分发事件:Window 对象会调用superDispatchTouchEvent 方法,将事件分发给对应的 ViewGroup 或View。

(3)ViewGroup 处理事件:ViewGroup 是一个布局容器,可以包含多个子视图。

ViewGroup 会根据事件的类型和当前触摸位置,决定将事件传递给哪个子视图或者自己处理。

(4)View 消费事件:View 是最基本的视图元素,它可以消费触摸事件并进行相应的处理。

如果 View 无法处理事件,会将事件传递给父容器。

3.事件分发中的关键角色在 Android 事件分发过程中,有三个关键角色:Activity、ViewGroup 和 View。

android事件分发理解 -回复

android事件分发理解 -回复

android事件分发理解-回复事件分发是Android系统中非常重要的一部分,它负责将用户的触摸、按键等操作传递给正确的组件或视图进行处理。

在这篇文章中,我们将深入探讨Android事件分发的机制以及其中涉及的关键概念。

首先,我们需要了解事件分发的基本原则。

在Android中,事件分发遵循着以下几个基本原则:1. 事件从最上层的视图开始,依次往下传递,直到找到合适的处理者。

这种传递方式有时也被称为“冒泡”或“捕获”。

2. 某个视图如果拦截了事件,那么它将成为事件的处理者,后续的传递过程将会被截断。

3. 如果某个视图没有拦截事件,那么事件将会继续往下传递,直到找到处理者或者传递到最底层的视图。

4. 如果没有合适的处理者,事件将被丢弃。

理解了这些基本原则后,我们可以开始分析Android事件分发的具体过程。

Android系统通过一个称为“事件分发链”的机制来实现事件的传递和处理。

事件分发链的顶层是ViewGroup类,它是所有视图容器的基类。

当用户进行触摸操作时,事件首先被传递给顶级的ViewGroup,然后由它开始向下传递。

在ViewGroup中,事件首先会经过一个称为“拦截事件”的过程。

在这个过程中,ViewGroup会根据自身的逻辑来判断是否要拦截事件,如果需要拦截,那么事件就会停止传递,并交给自身来处理。

如果ViewGroup决定不拦截事件,那么事件将会继续往下传递给其子视图。

在传递给子视图之前,ViewGroup会先对事件进行一些处理,比如调整坐标等。

子视图接收到事件后,会首先进行拦截事件的判断,判断依据可以是子视图自身的逻辑、触摸范围等。

如果子视图拦截了事件,那么它将会成为事件的处理者,并且接下来的传递过程将会被截断。

如果子视图不拦截事件,那么它会继续将事件传递给自己的子视图,以此类推,直到找到合适的处理者或传递到了最底层的视图。

一旦事件传递到合适的处理者,它将会执行相应的处理逻辑。

处理逻辑包括但不限于:触发点击事件、执行滑动操作等。

Android事件分发机制(上)ViewGroup的事件分发

Android事件分发机制(上)ViewGroup的事件分发

Android事件分发机制(上)ViewGroup的事件分发综述 Android中的事件分发机制也就是View与ViewGroup的对事件的分发与处理。

在ViewGroup的内部包含了许多View,⽽ViewGroup继承⾃View,所以ViewGroup本⾝也是⼀个View。

对于事件可以通过ViewGroup下发到它的⼦View并交由⼦View 进⾏处理,⽽ViewGroup本⾝也能够对事件做出处理。

下⾯就来详细分析⼀下ViewGroup对时间的分发处理。

MotionEvent 当⼿指接触到屏幕以后,所产⽣的⼀系列的事件中,都是由以下三种事件类型组成。

1. ACTION_DOWN: ⼿指按下屏幕 2. ACTION_MOVE: ⼿指在屏幕上移动 3. ACTION_UP: ⼿指从屏幕上抬起 例如⼀个简单的屏幕触摸动作触发了⼀系列Touch事件:ACTION_DOWN->ACTION_MOVE->…->ACTION_MOVE->ACTION_UP 对于Android中的这个事件分发机制,其中的这个事件指的就是MotionEvent。

⽽View的对事件的分发也是对MotionEvent 的分发操作。

可以通过getRawX和getRawY来获取事件相对于屏幕左上⾓的横纵坐标。

通过getX()和getY()来获取事件相对于当前View左上⾓的横纵坐标。

三个重要⽅法public boolean dispatchTouchEvent(MotionEvent ev) 这是⼀个对事件分发的⽅法。

如果⼀个事件传递给了当前的View,那么当前View⼀定会调⽤该⽅法。

对于dispatchTouchEvent的返回类型是boolean类型的,返回结果表⽰是否消耗了这个事件,如果返回的是true,就表明了这个View已经被消耗,不会再继续向下传递。

public boolean onInterceptTouchEvent(MotionEvent ev) 该⽅法存在于ViewGroup类中,对于View类并⽆此⽅法。

相关主题
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

Android焦点事件分发与传递机制下面我们就从源码来带大家进行安卓TV焦点事件的传递这里先给出Android系统View的绘制流程:依次执行View类里面的如下三个方法:measure(int ,int) :测量View的大小layout(int ,int ,int ,int) :设置子View的位置draw(Canvas) :绘制View内容到Canvas画布上ViewRootImpl的主要作用如下(此处不多讲,如有意图,看源码):A:链接WindowManager和DecorView的纽带,更广一点可以说是Window和View之间的纽带。

B:完成View的绘制过程,包括measure、layout、draw过程。

C:向DecorView分发收到的用户发起的event事件,如按键,触屏等事件。

ViewRootImpl不再多余叙述,进入正题:Android焦点分发的主要方法以及拦截方法的讲解。

在RootViewImpl中的函数通道是各种策略(InputStage)的组合,各策略负责的任务不同,如SyntheticInputStage、ViewPostImeInputStage、NativePostImeInputStage等等,这些策略以链表结构结构起来,当一个策略者没有消费事件时,就传递个下一个策略者。

其中触摸和按键事件由ViewPostImeInputStage处理。

@Overrideprotected int onProcess(QueuedInputEvent q) {if (q.mEvent instanceof KeyEvent) {return processKeyEvent(q);//如果是按键事件走此处,处理按键和焦点问题了} else {final int source = q.mEvent.getSource();if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {return processPointerEvent(q);//如果是触摸事件走此处} else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {return processTrackballEvent(q);} else {return processGenericMotionEvent(q);}}}processKeyEvent(QueuedInputEvent q)源码如下:@Overrideprotected void onDeliverToNext(QueuedInputEvent q) {if (mUnbufferedInputDispatch&& q.mEvent instanceof MotionEvent&& ((MotionEvent)q.mEvent).isTouchEvent()&& isTerminalInputEvent(q.mEvent)) {mUnbufferedInputDispatch = false;scheduleConsumeBatchedInput();}super.onDeliverToNext(q);}private int processKeyEvent(QueuedInputEvent q) {final KeyEvent event = (KeyEvent)q.mEvent;// Deliver the key to the view hierarchy.if (mView.dispatchKeyEvent(event)) {return FINISH_HANDLED;}if (shouldDropInputEvent(q)) {return FINISH_NOT_HANDLED;}// If the Control modifier is held, try to interpret the key as a shortcut. if (event.getAction() == KeyEvent.ACTION_DOWN&& event.isCtrlPressed()&& event.getRepeatCount() == 0&& !KeyEvent.isModifierKey(event.getKeyCode())) { if (mView.dispatchKeyShortcutEvent(event)) {return FINISH_HANDLED;}if (shouldDropInputEvent(q)) {return FINISH_NOT_HANDLED;}}// Apply the fallback event policy.if (mFallbackEventHandler.dispatchKeyEvent(event)) {return FINISH_HANDLED;}if (shouldDropInputEvent(q)) {return FINISH_NOT_HANDLED;}// Handle automatic focus changes.if (event.getAction() == KeyEvent.ACTION_DOWN) {int direction = 0;switch (event.getKeyCode()) {case KeyEvent.KEYCODE_DPAD_LEFT:if (event.hasNoModifiers()) {direction = View.FOCUS_LEFT;}break;case KeyEvent.KEYCODE_DPAD_RIGHT:if (event.hasNoModifiers()) {direction = View.FOCUS_RIGHT;}break;case KeyEvent.KEYCODE_DPAD_UP:if (event.hasNoModifiers()) {direction = View.FOCUS_UP;}break;case KeyEvent.KEYCODE_DPAD_DOWN:if (event.hasNoModifiers()) {direction = View.FOCUS_DOWN;}break;case KeyEvent.KEYCODE_TAB:if (event.hasNoModifiers()) {direction = View.FOCUS_FORW ARD;} else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) {direction = View.FOCUS_BACKWARD;}break;}if (direction != 0) {View focused = mView.findFocus();if (focused != null) {View v = focused.focusSearch(direction);if (v != null && v != focused) {// do the math the get the interesting rect// of previous focused into the coord system of// newly focused viewfocused.getFocusedRect(mTempRect);if (mView instanceof ViewGroup) {((ViewGroup)mView).offsetDescendantRectToMyCoords(focused, mTempRect);((ViewGroup) mView).offsetRectIntoDescendantCoords(v, mTempRect);}if (v.requestFocus(direction, mTempRect)) {playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction));return FINISH_HANDLED;}}// Give the focused view a last chance to handle the dpad key.if (mView.dispatchUnhandledMove(focused, direction)) {return FINISH_HANDLED;}} else {// find the best view to give focus to in this non-touch-mode with no-focusView v = focusSearch(null, direction);if (v != null && v.requestFocus(direction)) {return FINISH_HANDLED;}}}}return FORW ARD;}进入源码讲解:(1) 首先由dispatchKeyEvent进行焦点的分发如果dispatchKeyEvent方法返回true,那么下面的焦点查找步骤就不会继续了。

dispatchKeyEvent方法返回true代表事件(包括焦点和按键)被消费了。

dispatchKeyEvent(event)如果不了解,看我上一篇文章安卓TounchEvent事件分发机制。

mView的dispatchKeyEvent方法,mView是是Activity的顶层容器DecorView,它是一FrameLayout。

所以这里的dispatchKeyEvent方法应该执行的是ViewGroup的dispatchKeyEvent()方法,而不是View的dispatchKeyEvent方法。

@Overridepublic boolean dispatchKeyEvent(KeyEvent event) {if (mInputEventConsistencyVerifier != null) {mInputEventConsistencyVerifier.onKeyEvent(event, 1);}if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))== (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {if (super.dispatchKeyEvent(event)) {return true;}} else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS) == PFLAG_HAS_BOUNDS) {if (mFocused.dispatchKeyEvent(event)) {return true;}}if (mInputEventConsistencyVerifier != null) {mInputEventConsistencyVerifier.onUnhandledEvent(event, 1);}return false;}ViewGroup的dispatchKeyEvent简略执行流程首先ViewGroup会执行父类的dispatchKeyEvent方法,如果返回true那么父类的dispatchKeyEvent方法就会返回true,也就代表父类消费了该焦点事件,那么焦点事件自然就不会往下进行分发。

相关文档
最新文档