android触摸消息的派发过程

1.触摸消息是消息获取模块直接派发给应用程序的。
2.触摸消息在处理时, 需要根据触摸坐标计算该消息应该派发给哪个View/ViewGroup, 在案件取消处理中不存在 该计算过程。
3.没有类似”系统按键”的”系统触摸键”, 应用程序可完全控制触摸行为。
4.子视图优先父视图处理消息, 即首先是子视图处理该消息,只有当子视图消耗该消息时, 父视图才有机会处理 该消息。
触摸消息总体派发过程
1.进行物理像素到逻辑像素的转换。
2.如果是DOWN消息, 调用ensureTouchMode(true)函数则进入触摸模式,与之相反的是”非触摸模式”,即按键模式。
3.将屏幕坐标转换到视图坐标。
4.调用mView.dispathTouchEvent()将消息派发给根视图,该函数内部会继而将消息派发到整个View树。
5.如果以上根视图以及其所有子视图都没有消耗该消息,最后处理屏幕边界偏移。屏幕边界偏移在程序中用英文edge slop表示,它的作用是当用户正好触摸到屏幕边界时,系统自动对原始消息进行一定的偏移,然后在新的偏移后的位置上寻找是否有匹配的视图,如果有则将消息派发到该视图。
根视图内部消息派发过程
首先来看mView.dispatchTouchEvent()的派发过程。该函数是在ViewRoot中调用的,mView的类型可能有两种情况,对于应用窗口而言,mView是一个PhoneWindow中的DecorView类型,对于非应用窗口而言,mView是一般的ViewGroup类型。
在DecorView中,首先判断是否存在Callback对象,它和按键消息派发时的Callback对象一样,就是Activity类。如果没有Callback对象,则直接调用DecorView基类ViewGroup中的dispatchTouchEvent()函数。
在Activity中,dispatchTouchEvent()的过程如下。
1、如果ACTION_DOWN消息,则调用onUserInteraction()。
2、调用所包含的Window对象的superDispatchTouchEvent()。
3、如果Window类没有消耗该消息,则调用onTouchEvent()。
下面看看Window类中的superDispatchTouchEvent()。此时Window类的实现就是PhoneWindow类,该函数继而调用mDecor的superDispatchTouchEvent(),而在DecorView的该函数中又调用super.dispatchTouchEvent,即ViewGroup的dispatchTouchEvent函数。注意这里的调用过程,一般的消耗处理流程是当上一步没有消耗消息时才执行下一个处理逻辑,而在跟视图DecorView中,则是当没有Callback时才调用ViewGroup的消息处理逻辑,而不是当Callback没有消耗消息时才调用ViewGroup的消息处理逻辑,原因就是Callback本身就会调用ViewGroup的消息处理逻辑。
ViewGroup的内部消息派发过程
ViewGroup内部的处理逻辑也采用递归方式,但与按键处理的递归有所不同。触摸消息处理中首先会把消息派发给View树中最后一个子视图,如果子视图没有消耗该消息,才递归派发给其父视图,而在按键消息处理时,递归的过程正好相反。
1、将布局左边转化为视图坐标。
为什么要转换呢?因为接下来要判断该坐标落到了该ViewGroup中的哪个子视图中,子视图的位置都是相对于该ViewGroup的视图坐标的。
2、处理DOWN消息,其作用是判断该视图坐标落到了哪个子视图中。
(1)首先判断ViewGroup本身是否被禁止获取Touch消息,如果没有禁止,并且回调函数onInterceptTouchEvent()中没有消耗该消息,则意味着该消息可以传递给子视图。如果子视图消耗了该DOWN消息,则直接返回true。
(2)开始寻找子视图。调用child.getHitRect(frame)函数获取该子视图在父视图中的布局坐标,即该ViewGroup为该child分配的位置是什么,这个位置相对于该child来讲是布局坐标,而相对于ViewGroup来讲却是视图坐标,参数frame是执行完毕后的位置输出矩形。得到位置后,就可以调用frame.contain()方法判断该消息位置是否被包含到了该child中,如果包含,并且该child也是一个ViewGroup,则准备递归调用该child的dispatchTouchEvent(),在调用之前,首先需要把坐标重新转换到child的坐标系中。
(3)完成了递归操作钱的坐标转换工作,接下来判断该child是否是ViewGroup类。如果是就递归调用到ViewGroup的dispatchTouchEvent(),重新从第一步开始执行,如果child不是ViewGroup,而是一个View,则意味着递归调用的结束。
3、如果是UP活着CANCEL消息,则消除mGroupFlags中的FLAG_DISALLOW_INTERCEPT标识,即允许该ViewGroup截获消息。
4、判断target变量是否为空。空代表了所有的子窗口没有消耗该消息,所以该ViewGroup本身需要处理该消息。在第二步中,如果匹配到某个child, 并且该child消耗了消息后,会将该child赋值给父视图中的mMotionTarget变量。在该步中,首先要还原消息的原始位置,因为在第二步中,为了判断子视图是否包含该消息中的位置,对位置进行了从布局坐标到视图坐标的转换,而此时则需要把视图坐标重新转换为布局坐标,因为接下来要调用super.dispatchTouchEvent(),即View类的该函数。View类中处理该函数时,需要布局坐标。转换之后,直接调用super.dispatchTouchEvent(),并返回其执行结果,该函数内部仅仅是回调onTouchEvent(),调用之前先判断mPrivateFlags中是否包含CANCEL_NEXT_UP_EVENT标识,该表示一般情况下不会存在,如果存在,则将消息的action类型改为ACTION_CANCEL。
5、处理target存在,并且变量disallowInercept为false;即允许截获,在默认况下ViewGroup都是允许截获消息的,只有当该ViewGroup的子视图调用父视图的requestDisallowInterceptTouchEvent()函数时,方可禁止父视图再次截获消息。但每次UP消息或者CANCEL消息之后,该Viewgroup又会重新截获信息。注意,在本步中,如果不允许截获消息,那么也就不会调用onInterceptTouchEvent()函数了,如果允许,并且onTerceptTouchEvent()消耗了该消息,才执行本步的操作。
6、在大多数情况下都会执行到该步,即target存在,并且ViewGroup本身不允许截获消息或者允许截获但是却没有消耗消息,于是调用target.dispatchTouchEvent()把该消息继续交给目标视图处理。在调用该函数前需要检查target中是否声明过要取消随后的消息,即mPrivateFlags中包含CANCEL_NEXT_UP_EVENT,如果是,则把消息action值修改为CANCEL,置空mMotionTarget变量,因为target不想处理接下来的消息,那么就可以认为没有target了。
以上就是Touch消息在ViewGroup内部的递归和派发,在这里注意区分onInterceptTouchEvent()和onTouchEvent()。
onInterceptTouchEvent()是在ViewGroup中定义的,即只有ViewGroup的子类能够重载该方法。而onTouchEvent()函数有两个定义,一个是在View类中定义的,所有View类的子类都可以重载该方法,包括ViewGroup,另一个是在Activity中定义的,用户Activity可以重载该函数。View系统的消息处理机制中,会先执行视图内部的onTouchEvent,如果没有处理,才会调用Activity中的onTouchEvent()。
另外,对于ViewGroup而言,在一般情况下会先调用onInterceptTouchEvent(),只有当该函数没有消耗掉消息,并且其包含的子视图也没有消耗掉该消息时,才会执行该ViewGroup的onTouchEvent()。而对于View而言,没有onInterceptTouchEvent()被调用。但并不是所有的消息处理过程都是先调用onInterceptTouchEvent(), 只有两种情况才会调用到onInterceptTouchEvent()。
1.即在以上第2步骤中,当时DOWN消息,并且ViewGroup允许截获消息时。
2.即在以上第5步骤中,当ViewGroup中存在target对象,并且允许截获消息时。
View内默认消息派发过程
1、调用onFilterTouchEventForSecurity() 处理窗口处于模糊显示状态下的消息。所谓的模糊显示是指,应用程序可以设置当前窗口为模糊状态,此时窗口内部的所有视图将显示为模糊效果。这样做的目的是为了隐藏窗口中的内容,对于其中各个视图而言,可以设置该视图的FILTER_TOUCHES_WHEN_OBSCURED标识,如果存在该标识,则意味着用户希望不要处理该消息。
2、回调视图监听者的onTouch()函数,如果监听者消耗了该消息,则直接返回。
3、调用onTouchEvent(),应用程序可以重载该函数,但如果没有重载的话,该函数内部有默认的执行方式,默认的执行流程如下:
(1)判断该视图是否为disable状态,如果是,什么都不做,返回true,即消耗该消息
(2)处理消息代理TouchDelegate。所谓的消息代理是指,可以给某个View指定一个消息处理代理,当View收到消息时,首先将该消息派发给其代理进行处理。如果代理内部消耗了该消息,则View不需要再进行任何处理;如果代理没有处理,则View继续按照默认的逻辑进行处理。该类的目的是为了扩大点击区。(没有实现)
(3)判断该视图是否是可以点击的,如果不可点击,则直接返回false,即不处理该消息。否则,真正开始执行触摸消息的默认处理逻辑,该逻辑中分别处理了ACTION_DOWN、MOVE和UP消息,
1⃣️在ACTION_DOWN消息中,给mPrivateFlags变量添加PRESSED标识,并将变量mHasPerformLongPress置为false,然后启动tap监测,即发送一个异步延迟消息,延迟时间为ViewConfigration.getTapTimeout()。
2⃣️对于触摸消息而言,消息本身没有repeat的属性,这与按键消息不同,一次触摸消息只有一个DOWN消息,接下来就是连续的MOVE消息,并最终以UP消息结束。
3⃣️处理ACTION_UP消息,代码中判断该UP消息是发生在哪一个检测时间段中,并据此进行不同的处理。
4、处理ACTION_CANCEL消息,这里只需要清除PRESSED标识,并改变视图状态,然后再关闭tap检测即可。
至此Touch消息的一次处理过程就结束了。

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

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

相关文章

python 交互式流程图_使用Python创建漂亮的交互式和弦图

python 交互式流程图Python中的数据可视化 (Data Visualization in Python) R vs Python is a constant tussle when it comes to what is the best language, according to data scientists. Though each language has it’s strengths, R, in my opinion has one cutting-edg…

机器学习解决什么问题_机器学习帮助解决水危机

机器学习解决什么问题According to Water.org and Lifewater International, out of 57 million people in Tanzania, 25 million do not have access to safe water. Women and children must travel each day multiple times to gather water when the safety of that water …

递归原来可以so easy|-连载(3)

本期我们再通过几个例子,加深递归的理解和熟练度。 上期有一个练习题:用递归逆序输出一个包含整型数据的链表。 先完成这个练习题。 对于程序员来说,代码是最好的沟通工具,什么都不说,上代码: public class…

Viewport3D 类Viewport3D 类Viewport3D 类

.NET Framework 类库Viewport3D 类更新:2007 年 11 月为三维可视内容提供呈现图面。命名空间: System.Windows.Controls程序集: PresentationFramework(在 PresentationFramework.dll 中)用于 XAML 的 XMLNS&#xf…

升级android 6.0系统

How to Fix errors by manually flashing Marshmallow update 镜像下载for nexus Factory image Step 1: Download the [Marshmallow factory image](http://www.theandroidsoul.com/download-mra58k-android-6-0-marshmallow-update-released-for-nexus-5-nexus-6-nexus-9-n…

AGC 022 B - GCD Sequence

题面在这里&#xff01; 锻炼脑子的小构造题。。。 一开始被 a[]<30000 且 序列 gcd 1所困扰&#xff0c;但是发现这并没有什么&#xff0c;因为我接下来发现了一种总是能构造出 序列和是6的倍数的方案。 首先如果 n3 的话输出样例&#xff0c;因为只有这种情况没法用我的方…

最接近原点的 k 个点_第K个最接近原点的位置

最接近原点的 k 个点In this article, I will be explaining to you one of the problems that you may find when tackling questions in data structures and algorithm. You will need some basic knowledge of data structures in order to understand the optimized solut…

网络浏览器如何工作

Behind the scenes of modern Web Browsers现代Web浏览器的幕后花絮 The Web Browser is inarguably the most common portal for users to access the web. The advancement of the web browsers (through the series of history) has led many traditional “thick clients”…

让自己的头脑极度开放

为什么80%的码农都做不了架构师&#xff1f;>>> 一. 头脑封闭和头脑开放 头脑封闭 你是否经常有这样的经历&#xff0c;在一次会议或者在一次小组讨论时&#xff0c;当你提出一个观点而被别人否定时&#xff0c;你非常急迫地去反驳别人&#xff0c;从而捍卫自己的尊…

简介DOTNET 编译原理 简介DOTNET 编译原理 简介DOTNET 编译原理

简介DOTNET 编译原理 相信大家都使用过 Dotnet &#xff0c;可能还有不少高手。不过我还要讲讲Dotnet的基础知识&#xff0c;Dotnet的编译原理。 Dotnet是一种建立在虚拟机上执行的语言&#xff0c;它直接生成 MSIL 的中间语言&#xff0c;再由DotNet编译器 JIT 解释映象为本机…

RecyclerView详细了解

关于RecyclerView大家都不陌生了&#xff0c;它的使用也越来越受欢迎&#xff0c;现在总体了解一下RecyclerView的作用&#xff0c;为什么会有RecyclerView呢&#xff0c;我用ListView也能干所有的事情啊&#xff0c;尺有所短&#xff0c;寸有所长&#xff0c;先来看看Recycler…

案例与案例之间的非常规排版

In 1929 the Cond Nast publishing group brought Russian-born Mehemed Fehmy Agha—who had been working for the German edition of Vogue magazine—to America as art director for House & Garden, Vanity Fair, and the senior edition of Vogue.1929年&#xff0c…

熊猫分发_熊猫新手:第二部分

熊猫分发This article is a continuation of a previous article which kick-started the journey to learning Python for data analysis. You can check out the previous article here: Pandas for Newbies: An Introduction Part I.本文是上一篇文章的延续&#xff0c;该文…

浅析微信支付:申请退款、退款回调接口、查询退款

本文是【浅析微信支付】系列文章的第八篇&#xff0c;主要讲解商户如何处理微信申请退款、退款回调、查询退款接口&#xff0c;其中有一些坑的地方&#xff0c;会着重强调。 浅析微信支付系列已经更新七篇了哟&#xff5e;&#xff0c;没有看过的朋友们可以看一下哦。 浅析微信…

view工作原理-计算视图大小的过程(onMeasure)

view的视图有两种情况&#xff1a; 内容型视图&#xff1a;由视图的内容决定其大小。图形型视图&#xff1a;父视图为view动态调整大小。 ### measure的本质 把视图布局使用的“相对值”转化成具体值的过程&#xff0c;即把WRAP_CONTENT,MATCH_PARENT转化为具体的值。 measur…

[转载]使用.net 2003中的ngen.exe编译.net程序

ngen.exe程序为.net 2003自带&#xff0c; 在&#xff1a;/windows/microsoft.net/framework/v1.1.4322目录下ngen.exe ngen能把.net框架的东西编译成机器码.... 网友&#xff1a;Visual Studio .NET 2003程序的运行速度怎么样&#xff0c;我有一个感觉&#xff0c;V…

基于Redis实现分布式锁实战

背景在很多互联网产品应用中&#xff0c;有些场景需要加锁处理&#xff0c;比如&#xff1a;秒杀&#xff0c;全局递增ID&#xff0c;楼层生成等等。大部分的解决方案是基于DB实现的&#xff0c;Redis为单进程单线程模式&#xff0c;采用队列模式将并发访问变成串行访问&#x…

数据分析 绩效_如何在绩效改善中使用数据分析

数据分析 绩效Imagine you need to do a bank transaction, but the website is so slow. The page takes so much time to load, all you can see is a blue circle.想象您需要进行银行交易&#xff0c;但是网站是如此缓慢。 该页面需要花费很多时间来加载&#xff0c;您只能看…

隐私策略_隐私图标

隐私策略During its 2020 Worldwide Developers Conference, Apple spent time on one of today’s hottest topics — privacy. During the past couple of years, Apple has been rolling out various public campaigns aiming to position itself as a company that respect…

Java中的数组

一、数组的定义type[] arrayName;type arrayName[]; 推荐第一种 二、数组的初始化 含义&#xff1a;所谓的初始化&#xff0c;就是为数组的数组元素分配内存空间&#xff0c;并为每个数组元素赋初始值 &#xff08;1&#xff09;静态初始化&#xff1a;arrayName new type[…