Android事件分发机制及如何解决事件冲突

事件分发是一个老生常谈的问题了,不管是面试亦或者开发中都可以用到,例如滑动冲突等,今天我们就来说说Android的事件分发机制。

什么是Android事件分发机制

事件分发本质就是对MotionEvent事件分发的过程。即当一个MotionEvent发生后,系统将这个点击事件传递到一个具体的View上。事件分发所采用的是责任制,也就是说谁拦截了事件,就由谁来处理该事件。

MotionEvent就是手指触摸屏幕后所产生的一系列事件,有四个经典事件分别是:

ACTION_DOWM:即手指刚接触到屏幕触发的事件

ACTION_MOVE:即手指在屏幕上移动时触发的事件

ACTION_UP:即手指抬起时触发的时间

ACTION_CANCELL:官方给出的解释是 当你的手指(或者其它)移动屏幕的时候会触发这个事件,比如当你的手指在屏幕上拖动一个listView或者一个ScrollView而不是去按上面的按钮时会触发这个事件。

当你点击屏幕的时候事件会先“走上一圈”看是否被拦截

点击事件传递的顺序在这里插入图片描述

如图所示 点击事件传递的顺序是 Activity—>ViewGroup—>View

事件分发由三个方法来完成:

dispatchTouchEvent 事件分发 ,用来进行事件的分发。如果事件能够传递给当前View,那么此方法一定会被调用,返回结果受当前View的onTouchEvent和下级View的dispatchTouchEvent方法的影响,表示是否消耗当前事件

onInterceptTouchEvent 事件拦截,在上述方法内部调用,对事件进行拦截。该方法只在ViewGroup中有,View(不包含 ViewGroup)是没有的。一旦拦截,则执行ViewGroup的onTouchEvent,在ViewGroup中处理事件,而不接着分发给View。且只调用一次,返回结果表示是否拦截当前事件

onTouchEvent 事件消费,在dispatchTouchEvent方法中调用,用来处理点击事件,返回结果表示是否消耗当前事件

接下来我们来看一下事件分发的流程图方便大家理解:

在这里插入图片描述

了解完事件分发机制的流程后,我们来说一下如何处理事件冲突

解决事件冲突

常见开发中事件冲突的有ScrollView与RecyclerView的滑动冲突、RecyclerView内嵌同时滑动同一方向

滑动冲突处理的规则

1.对于由于外部滑动和内部滑动方向不一致导致的滑动冲突,可以根据滑动的方向判断谁来拦截事件。

2.对于由于外部滑动方向和内部滑动方向一致导致的滑动冲突,可以根据业务需求,规定何时让外部View拦截事件,何时由内部View拦截事件。

处理滑动冲突的两种方式:

外部拦截法:事件会先经过父容器,所以我们可以在父容器中判断是否需要拦截该事件,需要就拦截,不需要就不拦截。具体的实现方法,通过
onInterceptTouchEvent()方法返回true就会拦截该事件,交由本层的onTouchEvent()方法处理,返回false事件就会传递到下层。

内部拦截法:当父容器不对事件进行拦截,事件将传递到子容器中,所以我们可以在子容器中判断是否需要消费该事件,需要就消费该事件,否则就交于父容器处理。具体实现要配合requestDisallowInterceptTouchEvent方法实现

感谢观看!