因为不了解Android事件分发机制,居然被实习生嘲笑了

Android事件分发

Android的事件分发机制是一个非常重要的知识点,是一个核心,又是一个难点,是Android开发人员必须要了解的概念,学会他,我们就可以解决滑动冲突等问题,比如在View嵌套的时候,外部滑动与内部滑动的方向一致,该如何处理,这就需要了解事件分发机制才能解决,事件分发通常与View、ViewGroup和Activity相关联,形成了一个复杂的机制。

我们知道当一个或多个手指触摸屏幕时,通常有四种类型的事件:

ACTION_DOWN:按下屏幕时发生,表示触摸事件开始,他是第一个发生的事件。
ACTION_UP:手指抬起,表示触摸事件结束。
ACTION_MOVE:手指按下屏幕,并且手指移动的距离超过了某个阈值
ACTION_CANCEL:事件已取消(不是由用户的行为引起的)

这些信息都被包含在MotionEvent中,ACTION_DOWN和ACTION_UP只有1个,而ACTION_MOVE可能存在多个,所谓的事件分发就是对MotionEvent事件分发的过程,就是找到一个能处理这个MotionEvent的View,过程由Activity开始、传到ViewGroup、最终再传到 View,但是响应的过程是从下到上,从子到父,这点很好理解,当我们点击一个按钮时,这个按钮可能被包含在ViewGroup中,事件先会从Activity中开始分发进行,如果Activity要自己处理,那么这个按钮就得不到事件信息,如果Activity是进行分发,那么接下来包裹这个按钮的ViewGroup就会得到处理,同样如果这个ViewGroup要进行拦截,那么这个按钮也得不到响应,不拦截的话最终事件会被这个按钮消费。

事件分发由三个很重要的方法控制,他们被定义在Activity、View、ViewGroup中,他们是:

Activity

public boolean dispatchTouchEvent(MotionEvent ev)public boolean onTouchEvent(MotionEvent ev);

ViewGroup:

public boolean dispatchTouchEvent(MotionEvent ev)public boolean onInterceptTouchEvent(MotionEvent ev);

public boolean onTouchEvent(MotionEvent ev);

View:

public boolean dispatchTouchEvent(MotionEvent ev)public boolean onTouchEvent(MotionEvent ev);

可以看到Activity中和View中都没有onInterceptTouchEvent,Android的事件分发就需要了解这三个方法,下面一一分析。

dispatchTouchEvent
他是事件分发处理函数,如果事件传递到了当前View,那么这个方法会被调用,返回结果表示是否消耗当前事件,false表示事件允许继续分发,返回true则表示该事件不再继续分发,有可能是当前View的onTouchEvent或者是子View的dispatchTouchEvent消费了。

不用我说,当发生点击操作时,会先从Activity的dispatchTouchEvent方法开始,然后依次传递给子视图,Activity的dispatchTouchEvent方法非常简单,首先判断是不是按下,如果是则调用一下onUserInteraction(虽然这个方法什么也没做),然后superDispatchTouchEvent方法经过层层调用,会传递到View或ViewGroup的dispatchTouchEvent中。

如果superDispatchTouchEvent返回true,则事件结束,表示有View已经消费了,false的话会传递给自身的onTouchEvent方法进行消费,表示所有的View的onTouchEvent的返回了false,没有人去处理这个事件,只能交给自己处理。

public boolean dispatchTouchEvent(MotionEvent ev) {
     
     if (ev.getAction() == MotionEvent.ACTION_DOWN) {
     
         onUserInteraction();
     }
     if (getWindow().superDispatchTouchEvent(ev)) {
     
         return true;
     }
     return onTouchEvent(ev);
 }

对上面加粗地方解释一下:如果还想深入了解,就需要看DecorView,但过程也不是很多。

在这里想象一下,在Activity中有个ViewGoup,他的dispatchTouchEvent方法true,当单击这个ViewGoup的时候,那么这里就直接结束了,如果返回false,那么会走Activity的onTouchEvent方法。

如果返回super.dispatchTouchEvent(ev),那么这里就麻烦了,会走onInterceptTouchEvent方法,如果onInterceptTouchEvent方法返回true,那么就代表他要拦截当前事件,他的onTouchEvent就会被调用。如果返回false,那么表示不拦截当前事件,会继续传递给它的子元素,子元素的dispatchTouchEvent方法就会被调用,然后反复这个过程直到事件被最终处理。

另外如果给这个View设置了OnTouchListener,那么OnTouchListener.onTouch方法就会被调用,这个事件如何处理就要看onTouch的返回值,如果返回true则onTouchEvent方法不会被调用。在onTouchEvent中,如果设置了OnClickListener,那么他的onClick就会被调用。

onInterceptTouchEvent
这个方法是在dispatchTouchEvent中调用的,用来判断是否拦截当前事件,如果当前View拦截了事件,那么在后续同一个事件序列中,这个方法不会被再次调用,默认返回false,返回true表示拦截。

所以,在上一张图

因为不了解Android事件分发机制,居然被实习生嘲笑了_第1张图片

onTouchEvent
也在dispatchTouchEvent中调用,用来处理点击事件,如果返回true,则表示当前View消耗了此事件。

常见解决方案
ScrollView嵌套ScrollView
假设现在有两个ScrollView,每个ScrollView都需要上下滑动,如果不解决,那就是这个样子。

因为不了解Android事件分发机制,居然被实习生嘲笑了_第2张图片

只需自定义一个ScrollView,在onInterceptTouchEvent下这样写,即可解决。requestDisallowInterceptTouchEvent用于请求父view不要拦截Touch事件,也就是让父View不要管onInterceptTouchEvent方法,直接执行向子View分发事件的逻辑。同样ListView嵌套ListView、ScrollView嵌套ListView也可以使用此办法,

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
     
    getParent().requestDisallowInterceptTouchEvent(true);
    return super.onInterceptTouchEvent(ev);
}

因为不了解Android事件分发机制,居然被实习生嘲笑了_第3张图片

收起软键盘
现在Activity中存有一个EditText和一个Button,现在要你单机按钮或者空白处的时候收起软键盘,你会怎么做?

首先明确的是,如果我们不做一些手段,点击EditText使软键盘弹出后在点任何其他方,软键盘是不会收回的,了解了事件分发后,就可以利用Activity中的dispatchTouchEvent处理,在其中判断如果事件是ACTION_DOWN时,获取当前具有焦点的View,然后隐藏软键盘即可。

因为不了解Android事件分发机制,居然被实习生嘲笑了_第4张图片

@Override
 public boolean dispatchTouchEvent(MotionEvent ev) {
     
     if (ev.getAction()==MotionEvent.ACTION_DOWN){
     
         View v = getCurrentFocus();
         InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
         if (imm != null && v!=null) {
     
             imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
         }
     }
     return super.dispatchTouchEvent(ev);
 }

如果你近期正好有学习的计划,在这我也分享一份大佬收录整理的Android学习PDF+架构视频+面试文档+源码笔记,高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料
因为不了解Android事件分发机制,居然被实习生嘲笑了_第5张图片
这些都是我现在闲暇还会反复翻阅的精品资料。里面对近几年的大厂面试高频知识点都有详细的讲解。相信可以有效的帮助大家掌握知识、理解原理。

因为不了解Android事件分发机制,居然被实习生嘲笑了_第6张图片
也可以拿去查漏补缺,提升自身的竞争力。

如果你有需要的话,只需私信我【资料】即可获取

你可能感兴趣的:(程序员,android,编程语言)