Android事件分发机制简记

    xiaoxiao2021-04-18  44

    基础认知

    当用户触摸屏幕时(View或ViewGroup派生的控件),将产生点击事件(Touch事件)

    Touch事件相关细节(发生触摸的位置、时间、历史记录、手势动作等)被封装成MotionEvent对象

    主要发生的Touch事件有如下四种

    MotionEvent.ACTION_DOWN:按下View(所有事件的开始)

    MotionEvent.ACTION_MOVE:滑动View

    MotionEvent.ACTION_CANCEL:非人为原因结束本次事件

    MotionEvent.ACTION_UP:抬起View(与DOWN对应)

    Android的UI界面是由Activity、ViewGroup、View及其派生类组合而成的

    View是所有UI组件的基类

    一般Button、ImageView、TextView等控件都是继承父类View

    ViewGroup是容纳UI组件的容器,即一组View的集合(包含很多子View和子VewGroup)

    其本身也是从View派生的,即ViewGroup是View的子类

    是Android所有布局的父类或间接父类:项目用到的布局(LinearLayout、RelativeLayout等),都继承自ViewGroup,即属于ViewGroup子类。

    与普通View的区别:ViewGroup实际上也是一个View,只不过比起View,它多了可以包含子View和定义布局参数的功能。

    Android事件分发机制的本质是要解决:点击事件由哪个对象发出,经过哪些对象,最终达到哪个对象并最终得到处理。

    这里的对象是指Activity、ViewGroup、View

    Android中事件分发顺序:Activity(Window) -> ViewGroup -> View

    事件分发过程由dispatchTouchEvent() 、onInterceptTouchEvent()和onTouchEvent()三个方法协助完成

    Activity的事件分发机制

    当一个点击事件发生时,事件最先传到Activity的dispatchTouchEvent()进行事件分发,最终是调用了ViewGroup的dispatchTouchEvent()方法

    如果ViewGroup的dispatchTouchEvent()返回true就不执行Activity的onTouchEvent()方法;如果返回false,就执行。

    这样事件就从 Activity 传递到了 ViewGroup

    ViewGroup事件的分发机制

    Android事件分发是先传递到ViewGroup,再由ViewGroup传递到View

    在ViewGroup中通过onInterceptTouchEvent()对事件传递进行拦截

    onInterceptTouchEvent方法返回true代表拦截事件,即不允许事件继续向子View传递;

    返回false代表不拦截事件,即允许事件继续向子View传递;(默认返回false)

    子View中如果将传递的事件消费掉,ViewGroup中将无法接收到任何事件。

    View事件的分发机制

    onTouch()的执行高于onClick()

    每当控件被点击时:

    如果在回调onTouch()里返回false,就会让dispatchTouchEvent方法返回false,那么就会执行onTouchEvent();

    如果回调了setOnClickListener()来给控件注册点击事件的话,最后会在performClick()方法里回调onClick()。

    onTouch()返回false(该事件没被onTouch()消费掉) = dispatchTouchEvent()返回false(继续向下传递) = 执行onTouchEvent() = 执行OnClick()

    如果在回调onTouch()里返回true,就会让dispatchTouchEvent方法返回true,那么将不会执行onTouchEvent(),即onClick()也不会执行;

    onTouch()返回true(该事件被onTouch()消费掉) = dispatchTouchEvent()返回true(不会再继续向下传递) = 不会执行onTouchEvent() = 不会执行OnClick()

    思考点

    onTouch()和onTouchEvent()的区别

    这两个方法都是在View的dispatchTouchEvent中调用,但onTouch优先于onTouchEvent执行。

    如果在onTouch方法中返回true将事件消费掉,onTouchEvent()将不会再执行。

    如果你有一个控件是非enable的,那么给它注册onTouch事件将永远得不到执行。对于这一类控件,如果我们想要监听它的touch事件,就必须通过在该控件中重写onTouchEvent方法来实现。

    Touch事件的后续事件(MOVE、UP)层级传递

    如果给控件注册了Touch事件,每次点击都会触发一系列action事件(ACTION_DOWN,ACTION_MOVE,ACTION_UP等)

    当dispatchTouchEvent在进行事件分发的时候,只有前一个事件(如ACTION_DOWN)返回true,才会收到后一个事件(ACTION_MOVE和ACTION_UP),即如果在执行ACTION_DOWN时返回false,后面一系列的ACTION_MOVE和ACTION_UP事件都不会执行

    dispatchTouchEvent()和 onTouchEvent()消费事件、终结事件传递(返回true)而onInterceptTouchEvent 并不能消费事件,它相当于是一个分叉口起到分流导流的作用,对后续的ACTION_MOVE和ACTION_UP事件接收起到非常大的作用

    请记住:接收了ACTION_DOWN事件的函数不一定能收到后续事件(ACTION_MOVE、ACTION_UP)

    如果在某个对象(Activity、ViewGroup、View)的dispatchTouchEvent()消费事件(返回true),那么收到ACTION_DOWN的函数也能收到ACTION_MOVE和ACTION_UP

    如果在某个对象(Activity、ViewGroup、View)的onTouchEvent()消费事件(返回true),那么ACTION_MOVE和ACTION_UP的事件从上往下传到这个View后就不再往下传递了,而直接传给自己的onTouchEvent()并结束本次事件传递过程

    转载请注明原文地址: https://ju.6miu.com/read-674470.html

    最新回复(0)