安卓之事件分发机制

news2024/11/26 8:18:49

安卓之事件分发机制

简介

  • 事件分发的”事件“是指什么?
    答:点击事件(Touch事件)。
  • 当用户触摸屏幕(VIew或ViewGroup)时,将产生点击事件,即Touch事件。Touch事件的细节(如:触摸位置、事件等)会被封装成MotionEvent对象。
  • 常见的事件:
    • MotionEvent.ACTION_DOWN:按下。
    • MotionEvent.ACTION_UP:抬起。
    • MotionEvent.ACTION_MOVE:滑动。
    • MotionEvent.ACTION_CANCEL:结束事件(非正常情况)。
  • 事件列:指从手指接触屏幕至手指离开屏幕这个过程产生的一系列事件。
    • 一般情况下,事件列都是以DOWN事件开始、UP事件结束,中间有无数的MOVE事件。

本质

  • 事件分发的本质是将点击事件(MotionEvent)传递到某个具体的View进行处理的整个过程。即:事件传递的过程 = 分发过程

事件在哪些对象之间进行传递?

  • 答:Activity、ViewGroup、View。

事件分发的顺序是?

  • 答:Activity -> ViewGroup -> View。

事件分发过程由哪些方法协作完成?

  • 答:dispatchTouchEvent() 、onInterceptTouchEvent()和onTouchEvent()。
    在这里插入图片描述

Activity的事件分发机制

当用户触摸屏幕时,底层的 InputManager 会将触摸事件封装为 MotionEvent 对象,然后将该对象传递给当前 Activity 的 PhoneWindow 对象。PhoneWindow 对象会将该 MotionEvent 传递给 DecorView 对象,DecorView 再传递给Atcivity的 dispatchTouchEvent() 方法进行事件分发或处理。Atcivity的 dispatchTouchEvent() 方法如下:

  •  public boolean dispatchTouchEvent(MotionEvent ev) {
         ...
         if (getWindow().superDispatchTouchEvent(ev)) {
             return true;
         }
         return onTouchEvent(ev);
     }
    

View的事件分发机制

  • 先看源码:
    •  public boolean dispatchTouchEvent(MotionEvent event) {
       	//...省略代码
       	//以下为核心代码:
       	//这里就是View在收到事件后的具体处理逻辑了,也就是ViewGroup调用了View的dispatchTouchEvent()方法把事件传递给了View
       	//先判断有没有给View设置OnTouchListener,如果有就执行OnTouchListener的onTouch()方法
       	//同时该方法有返回值表示事件有没有被消费,如果被消费了,result设置为true
       	//接着是判断如果没有被消费,则执行onTouchEvent()方法,这个方法中会沿着MotionEvent.ACTION_UP->performClickInternal()->performClick()->OnClickListener的onClick(),最后走到了点击监听的onClick()中。
       	//同时,onClick()也是用返回值表示事件有没有被消费。
       	if (onFilterTouchEventForSecurity(event)) {
               if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) {
                   result = true;
               }
               //noinspection SimplifiableIfStatement
               ListenerInfo 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;
               }
           }
           //...省略代码
       }
      
  • 简单总结:
    • View中按onTouch()->onTouckEvent()->onClick()的顺序执行。
    • 同理,你的自定义View如果需要处理事件分发,那就在dispatchTouchEvent()方法中。
  • 以上就是View中最核心的事件分发处理流程了,同时延伸出几个可以提问的问题:
    • ①问:onTouch()和onClick()谁先执行?
         答:源码的顺序就是先走onTouch(),再走onClick()。
    • ②问:onTouch()方法返回值的作用?
         答:不仅仅是onTouch()方法,几乎所有的方法返回true表示事件被消费,返回false表示事件未被消费,可以继续分发。
    • ③问:onTouchEvent()一定执行吗?
         答:不一定,如果设置了OnTouchListener,则先看onTouch()拦不拦截,不拦截才会走onTouchEvent()方法。同时如果是自定义View,还要看有没有重写dispatchTouchEvent()方法。
    • ④问:onTouch()和onTouchEvent一定会执行吗?
         答:不一定,首先事件得先传递到dispatchTouchEvent()中,其次看各种条件是否能通过。
    • ⑤问:如何分析事件分发冲突?
         答:就是查看对应的控件的dispatchTouchEvent()是怎么么处理的,看事件有没有传递进去,传递进去后又是在哪消费的。
    • ⑥问:
    •     答:

Activity的事件分发机制

  • 先看源码:
    •  //事件是怎么传递到Activity的dispatchTouchEvent()方法中的?
       //		
       //Activity中进行分发:
       //		这里调用沿着getWindow().superDispatchTouchEvent(ev)
       //					->Window的唯一实现类PhoneWindow的mDecor.superDispatchTouchEvent(event)
       //					->DecorView的super.dispatchTouchEvent(event),
       //		最后传递到ViewGroup中,ViewGroup又进行事件分发。
       //
       //如果事件在Activity->ViewGroup->View整个传递过程中没有被处理,
       //最后又交回Activity的onTouchEvent()进行处理,
       //再如果Activity也不处理,那只能交给系统处理了。
       public boolean dispatchTouchEvent(MotionEvent ev) {
           if (ev.getAction() == MotionEvent.ACTION_DOWN) {
               onUserInteraction();
           }
           if (getWindow().superDispatchTouchEvent(ev)) {
               return true;
           }
           return onTouchEvent(ev);
       }
      

ViewGroup的事件分发机制

  • 先看源码:
    •  //第一块:ViewGroup每次事件分发时,都需调用onInterceptTouchEvent()询问是否拦截事件。
       //这里两个关键的地方:disallowIntercept和onInterceptTouchEvent()。
       //		disallowIntercept:是否禁用事件拦截的功能(默认是false),可通过调用requestDisallowInterceptTouchEvent()修改。
       //		onInterceptTouchEvent():
       //			a.若在onInterceptTouchEvent()中返回false,即当前ViewGroup不拦截事件。
       // 		b. 若在onInterceptTouchEvent()中返回true,即拦截事件。
       //			这个方法中一般就是解决事件分发冲突的,本质就是事件拦不拦截,交由谁处理。
       final boolean intercepted;
       if (actionMasked == MotionEvent.ACTION_DOWN
               || mFirstTouchTarget != null) {
           final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
           if (!disallowIntercept) {
               intercepted = onInterceptTouchEvent(ev);
               ev.setAction(action);
           } else {
               intercepted = false;
           }
       } else {
           intercepted = true;
       }
       
       //第二块:分发事件,看哪个子View处理事件
       //通过for循环,遍历当前ViewGroup下的所有子View,根据点击的位置判断当前遍历的View是不是正在点击的View,从而找到当前被点击的View。
       //dispatchTransformedTouchEvent()方法:内部根据传入的childView是否为空来决定调用当前View还是子View的dispatchTouchEvent()方法。
       if (!canceled && !intercepted) {
       	//..省略代码
          for (int i = childrenCount - 1; i >= 0; i--) {
              if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
                  mLastTouchDownTime = ev.getDownTime();
                  if (preorderedList != null) {
                      // childIndex points into presorted list, find original index
                      for (int j = 0; j < childrenCount; j++) {
                          if (children[childIndex] == mChildren[j]) {
                              mLastTouchDownIndex = j;
                              break;
                          }
                      }
                  } else {
                      mLastTouchDownIndex = childIndex;
                  }
                  mLastTouchDownX = ev.getX();
                  mLastTouchDownY = ev.getY();
                  newTouchTarget = addTouchTarget(child, idBitsToAssign);
                  alreadyDispatchedToNewTouchTarget = true;
                  break;
              }
              ev.setTargetAccessibilityFocus(false);
          }
       }
       
       //第三块:
       //执行事件。
       if (mFirstTouchTarget == null) {
           // No touch targets so treat this as an ordinary view.
           handled = dispatchTransformedTouchEvent(ev, canceled, null,
                   TouchTarget.ALL_POINTER_IDS);
       } else {
       	//...省略代码
       }
      

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/784904.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot整合MyBatisPlus入门

SpringBoot整合MyBatisPlus入门 1. MyBatisPlus概述1.1 MyBatis介绍1.2 MyBatisPlus特性 2. SpringBoot整合MyBatisPlus入门2.1 创建新模块&#xff0c;选择Spring初始化&#xff0c;并配置模块相关基础信息2.2 选择当前模块需要使用的依赖&#xff08;JDBC即可&#xff09;2.3…

【前端知识】React 基础巩固(三十一)——store数据的订阅和Redux的优化

React 基础巩固(三十一)——store数据的订阅和Redux的优化 一、store数据的订阅 store/index.js const { createStore } require("redux");// 初始化数据 const initialState {name: "test",title: "hello redux", };function reducer(state …

自然语言处理NLP介绍——NLP简介

目录 内容先进性说明内容大纲概要云服务器的使用 内容先进性说明 内容大纲概要 云服务器的使用

基于Java+SpringBoot+Vue+echarts健身房管理系统设计和实现

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

工作中的二三事(非技术 向)

DB更换节点导致系统无法访问案 XX年X月X日&#xff0c;周一。spotfire所有预加载全显示在排队状态&#xff0c;end user无法打开&#xff0c;良率无法及时汇报&#xff0c;影响挺大。 背景&#xff1a; 两台spotfire服务器 处理过程&#xff1a; 开始怀疑和另一现地的情况一…

阿里云远程调用接口api

1.云市场--->api--->搜索那你想要的功能 2.举例想要天气预报功能 3.用postman进行演示

【云计算小知识】云环境是什么意思?有什么优点?

随着云计算的快速发展&#xff0c;了解云计算相关知识也是运维人员必备的。那你知道云环境是什么意思&#xff1f;有什么优点&#xff1f;云环境安全威胁有哪些&#xff1f;如何保证云环境的运维安全&#xff1f;这里我们就来简单聊聊。 云环境是什么意思&#xff1f; 云环境是…

Linux系列---【Aerospike的介绍】

Aerospike的介绍 Aerospike(以下简称AS)是一个以分布式为核心基础&#xff0c;可基于行随机存取内存中索引、数据或SSD存储中数据的数据库。它主要用于百G、数T等大数据量并且在数万以上高并发情况下&#xff0c;对性能也有毫秒级读取插入要求的场景。 B站视频链接:https://www…

SWF格式视频怎么转换成AVI格式?简单的转换方法分享

当你想要在不同的设备上播放视频时&#xff0c;将SWF格式视频转换成AVI格式是非常有用的。因为SWF格式通常只能在特定的软件或网页上播放&#xff0c;而AVI格式则可以在更广泛的设备上播放&#xff0c;包括智能手机&#xff0c;平板电脑和电视机等。那么我们怎么将SWF转换成AVI…

数据库基础之——索引事务

索引&#xff08;index|key&#xff09; 1 概念 是数据库内部维护的一套数据结构&#xff0c;专门用于搜索的数据结构。目标就是提升搜索速度&#xff08;性能&#xff09;&#xff01; 数据存储的数据主要保存在硬盘上&#xff0c;维护的索引数据结构同样也保存在硬盘上。…

动手学DL——深度学习预备知识随笔【深度学习】【PyTorch】

文章目录 2、预备知识2.1、数据操作2.2、线性代数&矩阵计算2.3、导数2.4、基础优化方法 2、预备知识 2.1、数据操作 batch&#xff1a;以图片数据为例&#xff0c;一次读入的图片数量。 小批量样本可以充分利用GPU进行并行计算提高计算效率。 数据访问 数组&#xff1a;np…

mfc100u.dll丢失的4种解决方法分享,快速修复mfc100u.dll文件

在现代数字化时代&#xff0c;计算机已经成为了我们生活和工作的不可或缺的一部分。然而&#xff0c;随着软件的不断发展和更新&#xff0c;有时我们可能会遇到一些令人头疼的问题&#xff0c;例如MFC100U.DLL文件的丢失。当你第一次看到这个错误提示时&#xff0c;估计是一脸懵…

学好Elasticsearch系列-核心概念

本文已收录至Github&#xff0c;推荐阅读 &#x1f449; Java随想录 文章目录 节点角色master&#xff1a;候选节点data&#xff1a;数据节点Ingest&#xff1a;预处理节点ml&#xff1a;机器学习节点remote_ cluster_ client&#xff1a;候选客户端节点transform&#xff1a;…

2022 China Open Source Report

| 翻译&#xff1a;黄绍雅、岳扬、刘文涛、李思颖 | 编辑&#xff1a;胡欣元 | 设计&#xff1a;胡欣元 As 2022 finally came to an end, we also emerged from the challenging years of the three-year-long COVID pandemic. The new edition of the "China Open Sourc…

【多选框、表格全选】element el-checkbox、el-table

话不多说 先看效果&#xff1a; 多选框&#xff1a; 表格全选&#xff1a; <template><div><div class"titleLabel"><div class"lineStyle"></div>统计部门</div><div style"display: flex"><e…

服务网格简介:探索现代微服务架构中的服务网格概念和价值

&#x1f337;&#x1f341; 博主 libin9iOak带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——libin9iOak的博客&#x1f390; &#x1f433; 《面试题大全》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33…

Tiktok最全客户开发以及运营攻略,建议收藏

Tiktok最近很多粉丝朋友问我要怎么做&#xff0c;今天就来分享一下如何利用Tiktok开发客户以及运营思路&#xff0c;文章略长&#xff0c;需要安装包看文末&#xff0c;喜欢的点赞加关注。 一、外贸企业为什么要做Tiktok‍ TikTok作为一个全球范围内流行的短视频平台&#xf…

Django3 模糊查询/filters.SearchFilter的使用,基于viewsets.ModelViewSet

背景描述 模型 from django.db import modelsfrom interfaces.validate import validate_include from testcases.models import Testcases from utils.base_models import BaseModel from utils.pure_validator import JSONValidatorclass Interfaces(BaseModel):id models…

嵌入式Linux驱动开发——常见框架梳理

前言 本文主要介绍了Linux驱动开发中一些常用的驱动框架&#xff0c;platform、input、iic、spi等&#xff0c;硬件平台使用的是正点原子的imx6ull开发板。 一&#xff1a;Pinctrl子系统、Gpio子系统 不管什么框架最后都是要追溯到配置IO的电气属性和复用功能 如果要使用外部…

一起学数据结构(1)——复杂度

目录 1. 时间复杂度&#xff1a; 1.1 时间复杂度的概念&#xff1a; 1.2 时间复杂度的表示及计算&#xff1a; 1.3 较为复杂的时间复杂度的计算&#xff1a; 2. 空间复杂度&#xff1a; 2.1 空间复杂度的概念&#xff1a; 2.2 空间复杂度的计算&#xff1a; 1. 时间复杂度…