关于Android触摸事件分发的原理详析

目录
  • 一:前言
  • 二:说在前面的知识
  • 三:整体流程
    • 1:activity
    • 2:window就是PhoneWindow
    • 3:view group
    • 4:view
  • 四:一些关键点
  • 五:从源码看触摸事件分发
  • 总结

一:前言

最近在学Android的触摸事件分发,我觉得网上说的太杂太乱,而且有很多博客都有明显的错误。什么自顶向下分发,自下向顶分发,什么拦截又一直消费什么什么之类,非常难懂。为了自己将来回顾可以更好的理解这块知识,也为了后来之人可以更好的学习,我写下这篇博客。

二:说在前面的知识

  • 点击,滑动,松手都是由MotionEvent这个类来表示。
  • 屏幕上的一个事件序列是指以一个MotionEvent.action_down按下开始,以若干个MotionEvent.action_move移动事件在中间,再以一个MotionEvent.action_up作为结束的事件流。
  • view group是view的子类。view group和view都有dispatchTouchEvent方法;view group有onTnterceptTouchEvent和onTouchEvent方法,view 只有onTouchEvent方法。

三:整体流程

1:activity

我们点击屏幕的所有事件,都会被第一个接收。

public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            onUserInteraction();//是一个空方法,如果想知道按下了屏幕,可以重写这个方法打印日志
        }
        if (getWindow().superDispatchTouchEvent(ev)) {//把这个事件传给window属性
            return true;
        }
        return onTouchEvent(ev);
    }

2:window就是PhoneWindow

每一个activity都会对应一个PhoneWindow(在onCreate方法之前、activity内部的attach方法中创建)。PhoneWindow含有一个decor view属性(setContentView中创建),phone window把事件传给decor view。 decor view继承于view group。点击事件现在传到decor view这里,就开始view group的事件分发逻辑了。

3:view group

view group收到点击事件, 进入dispatchTouchEvent, 如果满足以下二个条件中的任何一个条件:

  • 事件为down事件
  • 有一个子view或子view group在处理着事件流了
mFirstTouchTarget !=null

就进入判断,如果没有被禁用拦截(子view调用parent.requestDisallowed....)就执行, onInterceptTouchEvent代码。

如果决定拦截,后面还会把mFirstTouchTarget置为null,这样,之后就不会在调用onInterceptTouchEvent了。而且之后的事件流都会由这个view group的dispatchTouchEvent处理

如果不决定拦截,就遍历子view、子view group,挨个调用它们的dispatchTouchEvent如果没有人接收,那就调用自己的super.dispatchTouchEventview group的super.dispatchTouchEvent就是自己view那部分 的 dispatchTouchEvent

4:view

在view这一层,对于down事件,返回true就表示消费这个down事件之后的序列。具体看图。

view调用setOnTouchLIstener可以设置OnTouchListener,重写onTouch方法。从源码中可以看出,若onTouch返回true,将不再回调onTouchEvent方法。不回调onTouchEvent的话,那onClickListener也不能回调了。

四:一些关键点

即使有view消费着一组事件,事件流由底向上传递时,依然会调用每一个view group的intercept拦截方法判断是否拦截。当一个view group遍历它所有的子view没有一个接收时,就会进入view模式,调用自己继承于view的那一个dispatchTouchEvent方法。如果自己不接收,那会交给调用自己的dispatchTouchEvent的那个父view.

事件流没有什么自上而下,就是自下而上的。

ViewGroup的实现负责将触摸事件沿着控件树向子控件进行派发,而View的实现则主要用于事件接收与处理工作。当view group没有子view接收时,view group作为一个“view”去处理。

五:从源码看触摸事件分发

由于专栏关注自定义控件,所以关于系统如何从硬件获取触摸事件以及传递到Activity的dispatchTouchEvent就不详细分解,下面将从Activity的dispatchTouchEvent方法来一步步看事件是如何被分发传递的:

Activity中的dispatchTouchEvent:

    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            onUserInteraction();
        }
        if (getWindow().superDispatchTouchEvent(ev)) {
            return true;
        }
        return onTouchEvent(ev);
    }

其中onUserInteraction();是一个空实现,是系统留给我们的一个修改事件分发的一个方法,这里可以忽略。

所以实际上Activity的dispatchTouchEvent方法是调用的PhoneWindow的superDispatchTouchEvent方法,如果superDispatchTouchEvent返回false,没有消费掉事件,那么才会再交给activity的onTouchEvent方法去处理,从这个角度来讲,如果所有地方都没有消费掉事件,最后接收事件的会是Activity的onTouchEvent方法。

那么下面我们来看看PhoneWindow中的superDispatchTouchEvent方法:

    @Override
    public boolean superDispatchTouchEvent(MotionEvent event) {
        return mDecor.superDispatchTouchEvent(event);
    }

发现实际上调用的是DecorView对象mDecor的superDispatchTouchEvent方法,来看看DecorView的superDispatchTouchEvent方法:

        public boolean superDispatchTouchEvent(MotionEvent event) {
            return super.dispatchTouchEvent(event);
        }

调用的super.dispatchTouchEvent,而再来看看这个DecorView的继承关系:

private final class DecorView extends FrameLayout implements RootViewSurfaceTaker

所以调用的是FrameLayout中的dispatchTouchEvent方法,而FrameLayout并没有重写dispatchTouchEvent方法,所以实际调用的是FrameLayout的父类 ---> ViewGroup中的dispatchTouchEvent方法,下面这个图描述了从系统得到MotionEvent实际到传递给DecorView的super.dispatchTouchEvent的过程:

总结

到此这篇关于Android触摸事件分发原理的文章就介绍到这了,更多相关Android触摸事件分发原理内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Android 的触摸事件详解及示例代码

    由于触摸(Touch)而触发的事件 Android的事件:onClick, onScroll,onFling等等,都是由许多个Touch组成的.其中Touch的第一个状态肯定是ACTION_DOWN,表示按下了屏幕.之后,touch将会有后续事件,可能是: ACTION_MOVE //表示为移动手势 ACTION_UP //表示为离开屏幕 ACTION_CANCEL //表示取消手势,不会由用户产生,而是由程序产生的 一个Action_DOWN, n个ACTION_MOVE, 1个ACTION_

  • Android触摸事件传递机制

    前言:在Android开发中,经常会遇到触摸事件冲突,比如ViewPager的轮播图跟Fragment的划动事件冲突,或者轮播图跟下拉事件冲突,自定义view的事件处理等,本文章将会详细介绍Activity.View.ViewGroup三者的触摸事件传递机制,传递包括三个阶段:分发.拦截.消费. 本文章将会详细介绍Activity.View.ViewGroup三者的触摸事件传递机制,传递包括三个阶段:分发.拦截.消费. 一.触摸事件的类型 触摸事件对应的是 MotionEvent 类,事件类型主

  • Android触摸事件如何实现笔触画布详解

    前言 任何View都有触摸事件,经常在自定义控件时重写setOnTouchListener 本篇通过手绘图片来讲述这个知识点,下面话不多说了,来一起看看详细的介绍吧 本篇分为三个等级:一览图: 直线 曲线 笔触 LEVEL1:基础实现 在Activity中通过一个全屏的Bitmap创建的Canvas绘制 为ImageView添加触摸事件监听. 1.成员变量 ImageView mIdIvShow; float downX = 0; float downY = 0; float upX = 0;

  • Android触摸事件传递图解

    本博文讲解流程 TouchEvent相关事件简介 流程图分解讲解 总结与归纳 一.TouchEvent相关事件简介 android TouchEvent相关事件有  1 dispatchTouchEvent 这个方法用来分发TouchEvent  2 onInterceptTouchEvent 这个方法用来拦截TouchEvent  3 onTouchEvent 方法用来处理TouchEvent 比较特殊一点的是onInterceptTouchEvent 事件,在activity中和view中是

  • 简单讲解Android开发中触摸和点击事件的相关编程方法

    在Android上,不止一个途径来侦听用户和应用程序之间交互的事件.对于用户界面里的事件,侦听方法就是从与用户交互的特定视图对象截获这些事件.视图类提供了相应的手段. 在各种用来组建布局的视图类里面,你可能会注意到一些公共的回调方法看起来对用户界面事件有用.这些方法在该对象的相关动作发生时被Android框架调用.比如,当一个视图(如一个按钮)被触摸时,该对象上的onTouchEvent()方法会被调用.不过,为了侦听这个事件,你必须扩展这个类并重写该方法.很明显,扩展每个你想使用的视图对象(只

  • android中处理各种触摸事件的方法浅谈

    Android里有两个类android.view.GestureDetectorandroid.view.GestureDetector.SimpleOnGestureListener(另外android.widget.Gallery好像是更牛x的OnGestureListener )1)新建一个类继承SimpleOnGestureListener,HahaGestureDetectorListener可以实现以下event事件.boolean onDoubleTap(MotionEvent e

  • Android触摸事件传递机制初识

    前言 今天总结的一个知识点是Andorid中View事件传递机制,也是核心知识点,相信很多开发者在面对这个问题时候会觉得困惑,另外,View的另外一个难题滑动冲突,比如在ScrollView中嵌套ListView,都是上下滑动,这该如何解决呢,它解决的依据就是View事件的传递机制,所以开发者需要对View的事件传递机制有较深入的理解. 目录 Activity.View.ViewGroup三者关系 触摸事件类型 事件传递三个阶段 View事件传递机制 ViewGroup事件传递机制 小结 Act

  • 关于Android触摸事件分发的原理详析

    目录 一:前言 二:说在前面的知识 三:整体流程 1:activity 2:window就是PhoneWindow 3:view group 4:view 四:一些关键点 五:从源码看触摸事件分发 总结 一:前言 最近在学Android的触摸事件分发,我觉得网上说的太杂太乱,而且有很多博客都有明显的错误.什么自顶向下分发,自下向顶分发,什么拦截又一直消费什么什么之类,非常难懂.为了自己将来回顾可以更好的理解这块知识,也为了后来之人可以更好的学习,我写下这篇博客. 二:说在前面的知识 点击,滑动,

  • Android Handler机制的工作原理详析

    写在前面 上一次写完Binder学习笔记之后,再去看一遍Activity的启动流程,因为了解了Binder的基本原理,这次看印象会更深一点,学习效果也比以前好很多.本来打算直接来写Activity的启动流程的,但总觉得Handler也需要写一下,知道Handler和Binder的原理后,再去看Activity的启动流程,应该也没什么问题了.虽然网上已经有很多Handler相关的文章了,而且Handler机制的上层原理也并不难,还是决定写一下,因为我想构建自己的知识体系.也希望给看我博客的朋友们一

  • Android触摸事件的应用详解

    前言 上一篇讲了Android触摸事件的传递机制,具体可以看这里初识Android触摸事件传递机制.既然知道Android中触摸事件的传递分发,那么它能解决什么样的问题,在我们实际开发中如何应用,这点很重要,知道原理是为了解决问题而准备的.这篇文章的核心讲的如何解决View的滑动冲突,这个问题在日常开发中很常见,比如内部嵌套Fragment视图是左右滑动,外部用一个ScrollView来包含,可以上下滑动,如果不进行滑动冲突处理的话,就会造成外部滑动方向和内部滑动方向不一致. 目录 常见的滑动冲

  • Android之事件分发机制与冲突详解

    在日常的开发过程中,我们往往会在同一个界面中出现内外两层或者多层View同时滑动的现象,这个时候往往**会出现滑动冲突.面对滑动冲突,很多开发人员不知道从哪里入手,**即便稍微有点思路,也要费点时间才能解决.其实滑动冲突的解决是有一定的套路的. 下面主要针对Android开发中几种常见的滑动冲突及对应的解决方案来进行讲解 常见的滑动冲突场景! 目前常见的滑动冲突主要可以分为以下三种来概括: 外部滑动方向和内部View的滑动方向不一致,内部的View和外部的View的滑动方向是**互相垂直的,**

  • Android开发Input系统触摸事件分发

    目录 引言 1. InputDispatcher 收到触摸事件 1.1 截断策略查询 2. InputDispatcher 分发触摸事件 2.1 寻找触摸的窗口 2.1.1 根据坐标找到触摸窗口 2.1.2 保存窗口 结束 引言 Input系统: InputReader 处理触摸事件 分析了 InputReader 对触摸事件的处理流程,最终的结果是把触摸事件包装成 NotifyMotionArgs,然后分发给下一环.根据 Input系统: InputManagerService的创建与启动 可

  • Android Touch事件分发过程详解

    本文以实例形式讲述了Android Touch事件分发过程,对于深入理解与掌握Android程序设计有很大的帮助作用.具体分析如下: 首先,从一个简单示例入手: 先看一个示例如下图所示: 布局文件 : <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id=&

  • Android View 事件分发机制详解

    Android开发,触控无处不在.对于一些 不咋看源码的同学来说,多少对这块都会有一些疑惑.View事件的分发机制,不仅在做业务需求中会碰到这些问题,在一些面试笔试题中也常有人问,可谓是老生常谈了.我以前也看过很多人写的这方面的文章,不是说的太啰嗦就是太模糊,还有一些在细节上写的也有争议,故再次重新整理一下这块内容,十分钟让你搞明白View事件的分发机制. 说白了这些触控的事件分发机制就是弄清楚三个方法,dispatchTouchEvent(),OnInterceptTouchEvent(),o

  • Android AccessibilityService 事件分发原理分析总结

    目录 AccessibilityService 监听事件的调用逻辑 onAccessibilityEvent onIntercept AccessibilityService 事件的外部来源 AccessibilityServiceInfo AccessibilityManager AccessibilityManagerService AccessibilityServiceConnection 前言: 在了解了无障碍服务基础使用之后,我们来探究一下 AccessibilityService

  • Android Touch事件分发深入了解

    本文带着大家深入学习触摸事件的分发,具体内容如下 1. 触摸动作及事件序列 (1)触摸事件的动作 触摸动作一共有三种:ACTION_DOWN.ACTION_MOVE.ACTION_UP.当用户手指接触屏幕时,便产生一个动作为ACTION_DOWN的触摸事件,此时若用户的手指立即离开屏幕,会产生一个动作为ACTION_UP的触摸事件:若用户手指接触屏幕后继续滑动,当滑动距离超过了系统中预定义的距离常数,则产生一个动作为ACTION_MOVE的触摸事件,系统中预定义的用来判断用户手指在屏幕上的滑动是

  • 利用DrawerLayout和触摸事件分发实现抽屉侧滑效果

    本文实例为大家分享了DrawerLayout和触摸事件分发实现抽屉侧滑效果的具体代码,供大家参考,具体内容如下 效果展示 还是看代码实在,直接上菜了. 1.MainActivity的代码: public class MainActivity extends AppCompatActivity implements MyDraweLayout.GetPositionCallback { private List<ImageView> imageList; private ViewPager vi

随机推荐