事件分发

知识要点:

1.dispatchTouchEvent(MotionEvent ev)

2.onInterceptTouchEvent(MotionEvent ev)

3.onTouchEvent(MotionEvent ev)

一. 基础认知

1.1 事件分发的对象是谁?

    点击事件(Touch事件)

定义

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

    Touch事件的相关细节(发生触摸的位置、时间等)被封装成MotionEvent对象

事件类型(4种)


特别说明:事件列

 从手指接触屏幕 至 手指离开屏幕,这个过程产生的一系列事件。注:一般情况下,事件列都是以DOWN事件开始、UP事件结束,中间有无数的MOVE事件,如下图:


1.2 事件分发的本质

    将点击事件(MotionEvent)传递到某个具体的View & 处理的整个过程

即 事件传递的过程 = 分发过程。

1.3 事件在哪些对象之间进行传递?

    Activity、ViewGroup、View

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

1.4 事件分发的顺序

    即 事件传递的顺序:Activity -> ViewGroup -> View

1.5 事件分发过程由哪些方法协作完成?


二.分发流程



2.1 Activity    

dispatchTouchEvent(MotionEvent ev) -- 事件分发

    1.返回true 直接消费掉 ,没有分发; 

    2.返回false,不消费,但是触摸事件不做处理;

3.只有返回super.dispatchTouchEvent(ev)事件才会向子view分发,其实是调用了PhoneWindow的superDispatchTouchEvent(),进而调用了DecorView的superDispatchTouchEvent,里面又调用了super.dispatchTouchEvent(),而DecorView是一个FrameLayout

onTouchEvent(MotionEvent event) --事件处理

1.返回false和默认(super.onTouchEvent(event)),不做处理;

2.返回true,消费事件

2.2 ViewGroup

dispatchTouchEvent(MotionEvent ev) -- 事件分发

    1.返回true 事件被消费了, 事件未分发

    2.返回false 事件未分发,事件传递到父容器的onTouchEvent()

    3.只有返回super.dispatchTouchEvent(ev),事件才会向下走,里面会调用onInterceptTouchEvent()

onInterceptTouchEvent(MotionEvent ev) -- 事件拦截

1.返回true,事件拦截,调用自己的onTouchEvent()

    2.返回false,事件未拦截,分发给了子view

    3.super.onInterceptTouchEvent(ev)与返回false效果一样

onTouchEvent(MotionEvent event)

    1.返回false和super.onTouchEvent(event)事件不消费,事件传递给父容器

    2.返回true,事件会被消费

2.3 View

dispatchTouchEvent(MotionEvent event)

    因为它最小,没有子view,所以这个方法其实没有进行分发的能力

    1.返回true,事件被消费,

    2.返回false ,事件传递到父容器的onTouchEvent()

    3.只有返回super.dispatchTouchEvent(ev),事件才会向下走,里面会调用自己 onTouchEvent()

onTouchEvent(MotionEvent event)

    1.返回false和super.onTouchEvent(event)事件不消费,事件传递给父容器

    2.返回true,事件会被消费 

三.点击事件触发的位置及拦截

在onTouchEvent() 方法中MotionEvent.ACTION_UP中会调用performClick(),performClick()中会调用onClick()

拦截点击事件:

在父容器中重写onInterceptTouchEvent(MotionEvent ev),返回true,会走父容器的onTouchEvent()方法

四.setOnTouchListener()和onTouchEvent()关系

源码如下:

第7行会调用OnTouchListener.onTouch(this, event),在第11行,才会去调用onTouchEvent(event),所以setOnTouchListener的onTouch()方法先被调用,如果onTouch()方法返回true,事件被消费了,则onTouchEvent()方法不会调用.

五.滑动事件冲突

    父容器想获取左右滑动事件,子view想获取垂直滑动事件(如Viewpager中有ListView),都想获取事件,怎么办?

思路:

可以进行选择性的拦截事件,当水平滑动的距离大于垂直滑动的距离时,拦截事件

• getX()和getY():由这两个函数获得的x,y值是相对的坐标值,相对于父容器坐标。

• getRawX()和getRawY():有这两个函数获得的x,y值是绝对坐标,是相对于屏幕的。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容