大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。
Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺
原创性声明:本文系作者原创,转载请附原文地址:http://blog.csdn.net/a774057695/article/details/49336123
最近实在太忙,没有写多少东西,上次承诺写的东西还没有写。先写一个干货。
Android最让我开心和有成就感的就是可以实现自定义,追根朔源是开源带来的,出于普适性,google不会提供定制性特别强的视图组件,但是我们可以自己动手,丰衣足食。
但是,往往自定义的时候会出现好多问题,说到底是还没有吃透,我不推荐学生时期自学的时候过分追究原理,那个时期并不合适做这件事,那种闭关到世界第一再出关的苦学我也是不认可的。学习就是要循序渐进,慢慢吃透,扩展出去……
经常我们会在onTouch上遇到问题,想要将其做成控件,或者要重复的绘制,基本都要和他打交道。
遇到的问题可以总结为两类:
1. 不会
2. 不理想
不会处理的话,在学习了本文,再加上一些文章和实例,自己在实践中琢磨,应该就能搞定了。
不理想,往往是出现了冲突,理论上来说,在当前界面上有能力处理onTouch事件的东西都可以和平共处,冲突只是我们没有处理好而已。
我们来思考一下:
l 系统是从屏幕上取得了Touch事件,并发出消息
l 任意一个处理者都有接收事件的入口,而且是一致的
l 在事件消息传递的时候,它并没有像快递单一样写好了给谁,注意:很重要!
l 处理者按照一定的规则决定自己是否处理
好的,请允许我再这样说一句:“冲突”并不是android定义的冲突,而是我们自己定义的“冲突”。大家一定会骂,这TM说的什么东西,请往下看。
我想大家对View一路发展下去的东西应该是有点了解的,就不再罗嗦了。
Android系统中的每个ViewGroup的子类都具有下面三个和TouchEvent处理有关的方法:
1)public boolean dispatchTouchEvent(MotionEventev) 分发TouchEvent
2)public booleanonInterceptTouchEvent(MotionEvent ev) 拦截TouchEvent
3)public boolean onTouchEvent(MotionEvent ev) 处理TouchEvent
这里赘述一句,可能有同行会说是任意View的子类,需要注意的是,不是所有的view的子类还能容纳view的,也就是说没有子视图了,那么他就不会再分发了,也不会拦截,因为它是最终的处理者。
回到话题,大家往往熟悉的是onTouchEvent(MotionEvent ev),这没有什么问题,本质就是要处理Touch事件,大家直指目标。但是!Touch事件呢?往往大家给忽略了,认为系统一定会给你的,最后出现了不理想的事情,大家定义成了“冲突”。Android系统表示“呵呵”。这里我先给出结论:当前界面上任意的View子类视图都有机会拿到Touch消息,这个消息像是在隧道中传播,越在外层的视图容器越靠近隧道的入口,这意味他越早接触到这条消息。
那么我们思考一下,接触到这条消息就只有“拿走他”和“放过他”两种结局吗?从语言上来看,似乎我说了句废话,实质上,我们可以:
1. 完全不理他
2. 拿过来自己使用并不再将这个消息向下传递
3. 拿过来使用的同时且继续向下传递
消息是个神奇的东西,并不像一块糖,我吃了你就别想了。
好的,我们再回头看一下,dispatchTouchEvent(MotionEventev)是处理分发的,处理分发的,后两个之后再谈。想要干预系统的规则,我们肯定要处理消息的分发。
这里直接和大家看一下系统默认怎么分发,先给一个图:(注意,应该是center,我就偷懒不改了)
我们以ACTION_DOWN事件为例。
1.假定inner(center)是可以clickable的
系统的事件处理流程:
说明:
首先触摸事件发生时(例如ACTION_DOWN),由系统调用Activity的dispatchTouchEvent方法,分发该事件。
根据触摸事件的坐标,将此事件传递给out的dispatchTouchEvent处理,
out则调用onInterceptTouchEvent 判断事件是由自己处理,还是继续分发给子View。
(假设out不处理Touch事件)根据事件发生坐标,将事件传递给out的子View-middle。可能你已经体会到了,那种隧道传递感和按照位置的规则
Middle及Center中事件处理过程同上。
假定Center组件的clickable属性为true,表示其能处理Touch事件,故center中的onInterceptTouchEvent方法将事件默认传递给center自己的onTouchEvent方法处理。
至此,此Touch事件已被处理,不继续进行传递。
2.假定三个都不能click
事件处理流程:
是不是有种有想法要冒出来的感觉,冷静一下,我们再回头看一下那三个方法,我们开始是这样说的:
1)public boolean dispatchTouchEvent(MotionEventev) 分发TouchEvent
2)public booleanonInterceptTouchEvent(MotionEvent ev) 拦截TouchEvent
3)public boolean onTouchEvent(MotionEvent ev) 处理TouchEvent
其实说的并不准确,我们结合api文档内容来看,顺便给大家翻一下,献丑了,译的不准确的还请见谅并指出啊。
onTouchEvent:
Implement this method to handle touch screen motion events.
实现这个方法来处理 触摸屏幕运动事件
If this method is used to detect click actions, it is recommended that theactions be performed by implementing and calling performClick(). This willensure consistent system behavior, including:
如果这个方法被用来检测点击事件,我们建议实现并调用performClick()方法来生成事件。这将确保一致的系统行为,包括
obeying click sound preferences
dispatching OnClickListener calls
handling ACTION_CLICK when accessibility features are enabled
点击事件将在可获取的属性允许时被执行
onInterceptTouchEvent:
Implement this method to intercept all touch screen motion events. Thisallows you to watch events as they are dispatched to your children, and takeownership of the current gesture at any point.
实现这个方法去拦截所有的 触摸屏幕运动事件,这将允许你去观察这些事件是否适合分发给你的子view,并且在任意时机都可以获得当前手势的所有权
Using this function takes some care, as it has a fairly complicatedinteraction with View.onTouchEvent(MotionEvent), and using it requiresimplementing that method as well as this one in the correct way. Events will bereceived in the following order:
使用这个方法的时候要小心,它同View.onTouchEvent(MotionEvent)之间有着复杂的拦截机制,同时,使用它需要同时、正确的实现onTouchEvent和onInterceptTouchEvent。事件将会在以下条件下被获取
You will receive the down event here.
你会在这些情况下获得向下传递的事件
The down event will be handled either by a child of this view group, orgiven to your own onTouchEvent() method to handle; this means you should implementonTouchEvent() to return true, so you will continue to see the rest of thegesture (instead of looking for a parent view to handle it). Also, by returningtrue from onTouchEvent(), you will not receive any following events inonInterceptTouchEvent() and all touch processing must happen in onTouchEvent()like normal.
向下传递的时间将会被 子view或者自身的onTouchEvent() 处理。这意味你需要实现onTouchEvent() 并 return true,这样你可以继续监听剩余的手势(而不是眼睁睁的看着被你的父View给处理了)。同样,在onTouchEvent() 中返回true你不会再接收到由onInterceptTouchEvent()发出的后随事件,并且所有的touch事件将会(也必须在,否则没有人再去处理它了)在onTouchEvent()处理。
For as long as you return false from this function, each following event(up to and including the final up) will be delivered first here and then to thetarget’s onTouchEvent().
如果你在onInterceptTouchEvent ()中return false,所有的剩余事件(移动到哪里和在哪里抬起手指)都将会第一时间被发送到这里,然后才会送给目标(//据我理解,要是被处理了就不会发送了)
If you return true from here, you will not receive any following events:the target view will receive the same event but with the actionMotionEvent.ACTION_CANCEL, and all further events will be delivered to youronTouchEvent() method and no longer appear here.
如果你在onInterceptTouchEvent ()中return true,那么你将不会收到任何的后随事件(就像移动到哪里和在哪里抬起手指),目标view将会接收到除了MotionEvent.ACTION_CANCEL之外的所有的信息,而且是一样的。并且所有的未来可能发生的事件都将被传递到该处的onTouchEvent()并不会在onInterceptTouchEvent中出现。
感觉自己译的还不错,喝口茶happy下。
好的,结合API和那个图,我们应当明白了这样一个道理:对系统而言,消息是向下传递的,每个子View都会接收到,并判断是否截获,不截获就向下传递,截获就自己处理,而处理也是有说法的,自己搞不定,他会找他爹,是不是很通俗。表达的意思就是有些同行解读的onTouchEvent是从子类向父类寻找的,当然我对那样的解读持保留意见。
然后呢我们再来谈一个问题,有些同行认为:一个事件无法被两个消费者处理,本质上来说是有问题的。
我们有时的确有这样的需求,尤其是在Layout那个方向继承过来的时候。
我在前面说过,消息是个神奇的东西,我们要处理的事件,已经被系统变成了一种消息,一个消息只能被一个消费者消费,从上面的内容我们已经看得比较透彻了,但是一个事件可以被做成多个一样的消息。干一个不负责任的事情:
@Override
publicbooleandispatchTouchEvent(MotionEvent ev) {
//TODO Auto-generated method stub
this.onTouchEvent(ev);
returnsuper.dispatchTouchEvent(ev);
}
你觉得子view能接收到吗?你觉得当前的view能处理吗?
我想这一篇最核心的就是和大家分析了这些事件的分发处理机制,怎么解决自己需要处理的问题,我想大家心里已经有了答案。
原创性声明:本文系作者原创,转载请附原文地址:http://blog.csdn.net/a774057695/article/details/49336123
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/195070.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...