Framework事件机制-深扒onInterceptTouchEvent拦截流程解析

Framework事件机制-深扒onInterceptTouchEvent拦截流程解析

一、基本知识

1.事件分发的三个函数

事件的分发 dispatchTouchEvent()

事件的拦截 onInterceptTouchEvent()

事件的处理(消费) onTouchEvent()

2.事件分发的对象

被分发的对象是那些?被分发的对象是用户触摸屏幕而产生的点击事件,事件主要包括:按下、滑动、抬起与取消。这些事件被封装成MotionEvent对象。

MotionEvent.ACTION_DOWN 在屏幕按下时 MotionEvent.ACTION_MOVE 在屏幕上滑动时 MotionEvent.ACTION_UP 在屏幕抬起时 MotionEvent.ACTION_CANCLE 滑动超出控件边界时

3.分发事件的组件

分发事件的组件,也称为分发事件者,包括Activity、View和ViewGroup。它们三者的一般结构为:

二、事件处理流程

首先,我们需要了解事件处理中的几个方法:

1、在ViewGroup中,事件分为dispatchTouchEvent(事件的分发),onInterceptTouchEvent(事件的拦截),onTouchEvent(事件的处理)。

2、在View中,事件分为dispatchTouchEvent(事件的分发),onTouchEvent(事件的处理)。

下面是demo的界面结构,它是由两个自定义的ViewGroup和一个自定义的View组成,并分别重写了它们的以上几个方法。

其中MyViewGroupA代码如下:

public class MyViewGroupA extends LinearLayout { public MyViewGroupA(Context context) { super(context); } public MyViewGroupA(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { switch (ev.getAction()){ case MotionEvent.ACTION_DOWN: Log.i(“MyViewGroupA”,”dispatchTouchEvent_ACTION_DOWN”); break; case MotionEvent.ACTION_MOVE: Log.i(“MyViewGroupA”,”dispatchTouchEvent_ACTION_MOVE”); break; case MotionEvent.ACTION_UP: Log.i(“MyViewGroupA”,”dispatchTouchEvent_ACTION_UP”); break; } return super.dispatchTouchEvent(ev); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { switch (ev.getAction()){ case MotionEvent.ACTION_DOWN: Log.i(“MyViewGroupA”,”onInterceptTouchEvent_ACTION_DOWN”); break; case MotionEvent.ACTION_MOVE: Log.i(“MyViewGroupA”,”onInterceptTouchEvent_ACTION_MOVE”); break; case MotionEvent.ACTION_UP: Log.i(“MyViewGroupA”,”onInterceptTouchEvent_ACTION_UP”); break; } return super.onInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()){ case MotionEvent.ACTION_DOWN: Log.i(“MyViewGroupA”,”onTouchEvent_ACTION_DOWN”); break; case MotionEvent.ACTION_MOVE: Log.i(“MyViewGroupA”,”onTouchEvent_ACTION_MOVE”); break; case MotionEvent.ACTION_UP: Log.i(“MyViewGroupA”,”onTouchEvent_ACTION_UP”); break; } return super.onTouchEvent(event); }}

MyViewGroupB代码如下:

public class MyViewGroupB extends LinearLayout { public MyViewGroupB(Context context) { super(context); } public MyViewGroupB(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { switch (ev.getAction()){ case MotionEvent.ACTION_DOWN: Log.i(“MyViewGroupB”,”dispatchTouchEvent_ACTION_DOWN”); break; case MotionEvent.ACTION_MOVE: Log.i(“MyViewGroupB”,”dispatchTouchEvent_ACTION_MOVE”); break; case MotionEvent.ACTION_UP: Log.i(“MyViewGroupB”,”dispatchTouchEvent_ACTION_UP”); break; } return super.dispatchTouchEvent(ev); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { switch (ev.getAction()){ case MotionEvent.ACTION_DOWN: Log.i(“MyViewGroupB”,”onInterceptTouchEvent_ACTION_DOWN”); break; case MotionEvent.ACTION_MOVE: Log.i(“MyViewGroupB”,”onInterceptTouchEvent_ACTION_MOVE”); break; case MotionEvent.ACTION_UP: Log.i(“MyViewGroupB”,”onInterceptTouchEvent_ACTION_UP”); break; } return super.onInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()){ case MotionEvent.ACTION_DOWN: Log.i(“MyViewGroupB”,”onTouchEvent_ACTION_DOWN”); break; case MotionEvent.ACTION_MOVE: Log.i(“MyViewGroupB”,”onTouchEvent_ACTION_MOVE”); break; case MotionEvent.ACTION_UP: Log.i(“MyViewGroupB”,”onTouchEvent_ACTION_UP”); break; } return super.onTouchEvent(event); }}

MyView代码如下:

public class MyView extends View { public MyView(Context context) { super(context); } public MyView(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean dispatchTouchEvent(MotionEvent event) { switch (event.getAction()){ case MotionEvent.ACTION_DOWN: Log.i(“MyView”,”dispatchTouchEvent_ACTION_DOWN”); break; case MotionEvent.ACTION_MOVE: Log.i(“MyView”,”dispatchTouchEvent_ACTION_MOVE”); break; case MotionEvent.ACTION_UP: Log.i(“MyView”,”dispatchTouchEvent_ACTION_UP”); break; } return super.dispatchTouchEvent(event); } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()){ case MotionEvent.ACTION_DOWN: Log.i(“MyView”,”onTouchEvent_ACTION_DOWN”); break; case MotionEvent.ACTION_MOVE: Log.i(“MyView”,”onTouchEvent_ACTION_MOVE”); break; case MotionEvent.ACTION_UP: Log.i(“MyView”,”onTouchEvent_ACTION_UP”); break; } return super.onTouchEvent(event); }}

我们说过,事件传递是由上到下的,所以最外层的View首先对事件进行操作。而我们最外层是Activity,所以事件也是从这里开始。 Activity代码如下:

public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override public boolean dispatchTouchEvent(MotionEvent event) { switch (event.getAction()){ case MotionEvent.ACTION_DOWN: Log.i(“Activity”,”dispatchTouchEvent_ACTION_DOWN”); break; case MotionEvent.ACTION_MOVE: Log.i(“Activity”,”dispatchTouchEvent_ACTION_MOVE”); break; case MotionEvent.ACTION_UP: Log.i(“Activity”,”dispatchTouchEvent_ACTION_UP”); break; } return super.dispatchTouchEvent(event); } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()){ case MotionEvent.ACTION_DOWN: Log.i(“Activity”,”onTouchEvent_ACTION_DOWN”); break; case MotionEvent.ACTION_MOVE: Log.i(“Activity”,”onTouchEvent_ACTION_MOVE”); break; case MotionEvent.ACTION_UP: Log.i(“Activity”,”onTouchEvent_ACTION_UP”); break; } return super.onTouchEvent(event); }}

现在我们通过触摸MyView开始进行分析。虽然dispatchTouchEvent是事件开始的第一步,但是在开发中,我们通常很少改写它,所以我们下面只讨论其他两个方法。 1、对以上方法均不作处理,都返回super。这意味着我们既不拦截,也不消费。

大家看输出结果:

I/Activity: dispatchTouchEvent_ACTION_DOWNI/MyViewGroupA: dispatchTouchEvent_ACTION_DOWNI/MyViewGroupA: onInterceptTouchEvent_ACTION_DOWNI/MyViewGroupB: dispatchTouchEvent_ACTION_DOWNI/MyViewGroupB: onInterceptTouchEvent_ACTION_DOWNI/MyView: dispatchTouchEvent_ACTION_DOWNI/MyView: onTouchEvent_ACTION_DOWNI/MyViewGroupB: onTouchEvent_ACTION_DOWNI/MyViewGroupA: onTouchEvent_ACTION_DOWNI/Activity: onTouchEvent_ACTION_DOWNI/Activity: dispatchTouchEvent_ACTION_MOVEI/Activity: onTouchEvent_ACTION_MOVEI/Activity: dispatchTouchEvent_ACTION_UPI/Activity: onTouchEvent_ACTION_UP

结合输出结果,我们可以总结出以下的结论:

结合流程图,不难发现,如果我对事件既不拦截,也不消费,当触发ACTION_DOWN的时候,事件会经过Activity——MyViewGroupA——MyViewGroupB——MyView一层层的向下进行dispatchTouchEvent(分发)—onInterceptTouchEvent(拦截)调用。当到达最底层MyView后,开始触发消费操作,因为我均不消费,ACTION_DOWN将由底层一层层向上冒,移交上层处理。当抵达最上层Activity后,说明下层均不消费,之后触发的ACTION_MOVE和ACTION_UP将不再向下层分发传递,直接交由Activity分发给自己进行处理。

2、我们将MyVIewGroupB的onInterceptTouchEvent返回值改为true,其他均是super。这意味着仅仅MyViewGroupB进行事件拦截,但均无消费

输出结果如下:

I/Activity: dispatchTouchEvent_ACTION_DOWNI/MyViewGroupA: dispatchTouchEvent_ACTION_DOWNI/MyViewGroupA: onInterceptTouchEvent_ACTION_DOWNI/MyViewGroupB: dispatchTouchEvent_ACTION_DOWNI/MyViewGroupB: onInterceptTouchEvent_ACTION_DOWNI/MyViewGroupB: onTouchEvent_ACTION_DOWNI/MyViewGroupA: onTouchEvent_ACTION_DOWNI/Activity: onTouchEvent_ACTION_DOWNI/Activity: dispatchTouchEvent_ACTION_MOVEI/Activity: onTouchEvent_ACTION_MOVEI/Activity: dispatchTouchEvent_ACTION_UPI/Activity: onTouchEvent_ACTION_UP

结合输出结果,总结如下:

当触发ACTION_DOWN的时候,事件依然是从Activity开始一层层向下传递,当传递到MyViewGroupB时,因为进行了事件拦截,所以执行完onInterceptTouchEvent后不再向下传递,而是直接交由MyViewGroupB的onTouchEvent进行消费处理。由于我们是只拦截,不消费,所以事件向上传递,交由上层处理,最终回到Activity。之后触发的ACTION_MOVE和ACTION_UP也不再向下传递,直接交由Activity分发给自己处理。

3、我们还是将MyViewGroupB的onInterceptTouchEvent返回super,但是将他的onTouchEvent返回true。这意味着我们不拦截,但是由MyViewGroupB进行事件处理。

输出结果如下:

I/Activity: dispatchTouchEvent_ACTION_DOWNI/MyViewGroupA: dispatchTouchEvent_ACTION_DOWNI/MyViewGroupA: onInterceptTouchEvent_ACTION_DOWNI/MyViewGroupB: dispatchTouchEvent_ACTION_DOWNI/MyViewGroupB: onInterceptTouchEvent_ACTION_DOWNI/MyView: dispatchTouchEvent_ACTION_DOWNI/MyView: onTouchEvent_ACTION_DOWNI/MyViewGroupB: onTouchEvent_ACTION_DOWNI/Activity: dispatchTouchEvent_ACTION_MOVEI/MyViewGroupA: dispatchTouchEvent_ACTION_MOVEI/MyViewGroupA: onInterceptTouchEvent_ACTION_MOVEI/MyViewGroupB: dispatchTouchEvent_ACTION_MOVEI/MyViewGroupB: onTouchEvent_ACTION_MOVEI/Activity: dispatchTouchEvent_ACTION_UPI/MyViewGroupA: dispatchTouchEvent_ACTION_UPI/MyViewGroupA: onInterceptTouchEvent_ACTION_UPI/MyViewGroupB: dispatchTouchEvent_ACTION_UPI/MyViewGroupB: onTouchEvent_ACTION_UP

结合输出结果,总结如下:

可以看出,当触发ACTION_DOWN的时候,事件的分发传递过程和1的时候一样,从Activity开始一层层向下传递,最终传递到最底层MyView,触发消费操作,然后MyView将消费操作移交上层处理,然后到达MyViewGroupB的onTouchEvent,并且进行了消费处理,事件处理到此不在向上移交。当触发ACTION_MOVE和ACTION_UP操作时,事件依然需要由Activity开始向下分发传递,但是当传递到MyViewGroupB后,由于其消费了ACTION_DOWN,事件将不再继续向下分发,而是直接由MyViewGroupB分发给自己的onTouchEvent进行继续处理。事件处理也不再向上移交。

4、将MyViewGroupB的onInterceptTouchEvent和onTouchEvent的返回值均改为true。这意味着既拦截,又消费。

输出结果如下:

I/Activity: dispatchTouchEvent_ACTION_DOWNI/MyViewGroupA: dispatchTouchEvent_ACTION_DOWNI/MyViewGroupA: onInterceptTouchEvent_ACTION_DOWNI/MyViewGroupB: dispatchTouchEvent_ACTION_DOWNI/MyViewGroupB: onInterceptTouchEvent_ACTION_DOWNI/MyViewGroupB: onTouchEvent_ACTION_DOWNI/Activity: dispatchTouchEvent_ACTION_MOVEI/MyViewGroupA: dispatchTouchEvent_ACTION_MOVEI/MyViewGroupA: onInterceptTouchEvent_ACTION_MOVEI/MyViewGroupB: dispatchTouchEvent_ACTION_MOVEI/MyViewGroupB: onTouchEvent_ACTION_MOVEI/Activity: dispatchTouchEvent_ACTION_UPI/MyViewGroupA: dispatchTouchEvent_ACTION_UPI/MyViewGroupA: onInterceptTouchEvent_ACTION_UPI/MyViewGroupB: dispatchTouchEvent_ACTION_UPI/MyViewGroupB: onTouchEvent_ACTION_UP

结合输出结果,总结如下:

当触发ACTION_DOWN的时候,依然从Activity开始向下传递,当到达MyViewGroupB的是,因为在onInterceptTouchEvent进行了拦截操作,因此不再继续向下分发传递,而是交由MyViewGroupB的onTouchEvent进行处理消费。MyViewGroupB的onTouchEvent返回的是true,说明它决定对ACTION_DOWN进行处理,因此事件也就不再移交上层处理。当触发ACTION_MOVE和ACTION_UP的时候,事件还是从Activity开始向下传递,当到达MyViewGroupB的时候,由于之前进行了拦截操作,因此,MyViewGroupB直接将事件分发给自己的onTouchEvent进行处理,不在向下分发传递。事件处理也不再向上层移交。

三、文末

事件分发机制就犹如数学的定理是一样道理的,只有记住定理,才能在具体应用中具体分析,有人可能不知道在什么地方会用到,如果你做的项目中,比如有一个控件点击不能反应,那么就有可能是事件分发的结果。

至于对源码的分析可能内容比较复杂,内容也多;需要我这套framework进阶学习全套笔记的可以前往私信我;发送“核心笔记”或“手册”即可领取!整理不易!记得点赞分享哦!

郑重声明:本文内容及图片均整理自互联网,不代表本站立场,版权归原作者所有,如有侵权请联系管理员(admin#wlmqw.com)删除。
用户投稿
上一篇 2022年7月9日 21:17
下一篇 2022年7月9日 21:18

相关推荐

  • 分享4条发微商朋友圈的方法(微商朋友圈应该怎么发)

    对于微商朋友来说,朋友圈的重要性不言而喻了。 那么微商的朋友圈到底该怎么发呢? 为什么同样是经营一个朋友圈,有的微商看起来逼格满满,实际效果也不错;而有的却动都不动就被屏蔽甚至拉黑…

    2022年11月27日
  • 《宝可梦朱紫》梦特性怎么获得?隐藏特性获取方法推荐

    宝可梦朱紫里有很多宝可梦都是拥有梦特性会变强的宝可梦,很多玩家不知道梦特性怎么获得,下面就给大家带来宝可梦朱紫隐藏特性获取方法推荐,感兴趣的小伙伴一起来看看吧,希望能帮助到大家。 …

    2022年11月25日
  • 《宝可梦朱紫》奇鲁莉安怎么进化?奇鲁莉安进化方法分享

    宝可梦朱紫中的奇鲁莉安要怎么进化呢?很多玩家都不知道,下面就给大家带来宝可梦朱紫奇鲁莉安进化方法分享,感兴趣的小伙伴一起来看看吧,希望能帮助到大家。 奇鲁莉安进化方法分享 奇鲁莉安…

    2022年11月25日
  • 客服的岗位职责怎么写(客服工作内容及职责)

    各位小伙伴们大家周一好,又到了每周一给大家分享干货内容的时候啦~ 本期来跟大家分享一下客服工作管理流程以及客服岗位里面的每项职能岗位的核心细则,也是干货满满推荐收藏~ 一.补偿流程…

    2022年11月25日
  • 中兴Axon40 Ultra航天版将于11月29日正式发布

    据中兴手机官微爆料,中兴Axon40 Ultra航天版将于11月29日正式发布,新机不仅会采用骁龙处理器,还将为大家带来一枚独立安全芯片,获得国密认证,拥有安全专利布局,不仅可以大…

    2022年11月24日
  • 三星tabs8+配置参数 三星tabs8+屏幕尺寸处理器介绍

    三星Galaxy Tab S8+是2022年3月份上市的一款平板,有很多用户想了解一下这款平板的配置参数,下面我就给大家提供一下这款平板的参数配置。 三星Galaxy Tab S8…

    2022年11月24日
  • 淘宝直播开通后带货链接怎么做(淘宝直播需要开通淘宝店铺吗)

    直播带货无论是对于商家来说还是主播收益都是非常可观的,所以不少平台都有直播带货功能,一些小伙伴也想加入淘宝直播,那么淘宝直播开通后带货链接怎么做?下面小编为大家带来淘宝直播开通后带…

    2022年11月24日
  • 事件营销案例

    篇一成功营销案例小故事成功销售案例小故事篇1模仿 一个人想做一套家具,就走到树林里砍倒一棵树,并动手把它锯成木板这个人锯树的时候,把树干的一头搁在树墩上,自己骑在树干上还往锯开的缝…

    2022年11月24日
  • 《宝可梦朱紫》暴飞龙怎么抓?暴飞龙获得方法

    宝可梦朱紫暴飞龙位置在哪?在游戏中,很多玩家还不清楚暴飞龙具体要怎么样获得,其实获得方法很简单,暴飞龙直接是没得抓的,需要玩家从宝贝龙进化得到,下面一起来看一下宝可梦朱紫暴飞龙获得…

    2022年11月23日
  • 《宝可梦朱紫》布土拨怎么进化?布土拨进化方法介绍

    宝可梦朱紫中,不同的宝可梦有不同的进化方法,其中布土拨的进化方法是比较特殊的。很多玩家不知道宝可梦朱紫布土拨怎么进化,下面就带来宝可梦朱紫布土拨进化方法介绍,一起来看看吧,希望能帮…

    2022年11月23日

联系我们

联系邮箱:admin#wlmqw.com
工作时间:周一至周五,10:30-18:30,节假日休息