事件分发的对象是谁?点击事件(Touch事件)
定义:当用户触摸屏幕时(View 或 ViewGroup派生的控件),将产生点击事件(Touch事件)
Touch事件的相关细节(发生触摸的位置、时间等)被封装成MotionEvent对象
事件类型(4种)
事件类型具体动作
MotionEvent.ACTION_DOWN按下View(所有事件的开始)
MotionEvent.ACTION_UP抬起View(与DOWN对应)
MotionEvent.ACTION_MOVE滑动View
MotionEvent.ACTION_CANCEL结束事件(非人为原因)
特别说明:从手指接触屏幕 至 手指离开屏幕,这个过程产生的一系列事件
注:一般情况下,事件列都是以DOWN事件开始、UP事件结束,中间有无数的M
注:一般情况下,事件列都是以DOWN事件开始、UP事件结束,中间有无数的MOVE事件,如下图:
6666 6 6事件分发的本质
将点击事件(MotionEvent)传递到某个具体的View & 处理的整个过程
即 事件传递的过程 = 分发过程。
事件在哪些对象之间进行传递?
Activity、ViewGroup、View
Android的UI界面由Activity、ViewGroup、View 及其派生类组成
事件分发的顺序
即 事件传递的顺序:Activity -> ViewGroup -> View
事件分发过程由哪些方法协作完成?
什么是事件分发
通过手指对屏幕的触摸来完成整个交互过程
用户通过屏幕与手机交互的时候,每一次点击,长按,移动等都是一个事件
事件分发机制
某一个事件从屏幕传递各个View,由View来使用这以事件(消费事件)或者忽略
事件分发的对象是谁
系统把事件封装为MotionEvent对象,事件分发的过程就是MotionEvent分发的过程
事件的类型
按下(ACTION_DOWN)手指刚刚接触屏幕的时候手指按下的动作
移动 (ACTION_MOVE) 手指在屏幕上移动的一个动作在ACTION_DOWN之后并且不包括ACTION_DOWN
抬起(ACTION_UP) 表示手指抬起的一个动作
取消(ACTION_CANCEL) 表示事件的取消 举例:
父容器scollView 上有一个button按钮当我们按下button按钮不抬起而是滑动 scollView就会拦截这一个这一个
事件。同时button上也会接收这个事件表示当前这个点击事件已经取消了。、
事件序列
从手指按下屏幕开始,到手指离开屏幕所产生的一系列事件
事件的传递层级
手指无论触摸哪一个按钮或者子View,其实都是触摸到了我们activity之上
Activity---->Window---->DecorView---->ViewGroup---->View
事件传递所涉及到的三个主要对象
activity ViewGroup View
事件在Activity中传递的流程
dispatchTouchEvent(MotionEvent ev)
onTouchEvent(MotionEvent ev)
事件在调用dispatchTouchEvent()之后在分发的过程当中就会调用到onTouchEvent()
activity事件分发
首先调用activity的 dispatchTouchEvent()如果事件为一个按下事件的话
默认调用onUserInteraction()默认是一个空方法,会在整个事件开始的时候就会被立即调用到,如果我们
没有对这个方法进行重写的话,那么我们就不需关注它。
接下来就会调用getWindow().superDispatchTouchEvent(ev)从这里开始就正式进入了事件
派发的过程,这里事件开始交给activity所附属的Window进行派发,这个方法最终会一直调用
到ViewGroup中的dispatchTouchEvent()
如果getWindow().superDispatchTouchEvent(ev)返回为true那么
activity的dispatchTouchEvent()也返回为true,定义为事件被消费了
事件结束
如果说getWindow().superDispatchTouchEvent(ev)返回为false
就会调用activity.onTouchEvent() 它首先调用Window下的shouldCloseOnTouch()
判断事件是否在可响应的范围之内,activity.onTouchEvent()是返回true否返回false
Activityy.dispatchTouchEvent()返回值就等于activity.onTouchEvent()的返回值
无论返回什么事件都结束
Activity分发到ViewGroup中
dispatchTouchEvent()就会首先被调用到
onInterceptTouchEvent()事件分发的过程中会被调用
返回为true表示当前的ViewGroup会把事件拦截掉不会向下分发
返回为false当前的ViewGroup不会拦截掉这个事件
onTouchEvent()在View Group里面没有这个方法,是来自ViewGroup父类View的方法
ViewGroup让onInterceptTouchEvent()返回为true拦截掉事件 重写onTouchEvent()此方法处理触摸事件
ViewGroup事件流程
ViewGroup.dispatchTouchEvent()
主要做三件事
1去判断是否需要去拦截事件
2在当前的ViewGroup中找到用户真正触摸的子view
3分发事件到子View上
事件从ViewGroup.dispatchTouchEvent()进入
调用onFilterTouchEventForSecurity() 判断触摸事件是否符合安全策略
什么是安全策略:
如果用户点击的View 不在视图顶部 并且设置了当前View不在视图顶部不响应触摸事件,是不会响应我们的触摸事件的。
安全返回为true继续向下执行 不安全返回false事件未消费 结束分发
继续调用onInterceptTouchEvent() 对事件进行拦截处理 如果返回为true
表示拦截此事件不允许事件向子View传递 调用父类的(View)的dispatchTouchEvent()
自己处理该事件
返回为false 允许事件向子View 进行传递找到被点击的子View调用子View的dispatchTouchEvent()
ViewGroup事件结束
ViewGroup分发到View中
dispatchTouchEvent() 标志事件进入到view中了
onTouchEvent() 用户处理触摸事件的逻辑写在次方法中
流程
首先通过dispatchTouchEvent()进入
然后判断这个事件是否具有一个可响应的焦点 返回为false表示view不可响应
事件结束未被消费 返回为true事件继续执行
调用onFilterTouchEventForSecurity() 判断触摸事件是否符合安全策略 符合继续执行 不符合事件结束事件未被消费
继续判断是否是一个鼠标事件 如果为一个鼠标事件 直接返回为true 标志事件被消费了事件结束
继续判断view是否设置了touchListener触摸事件的监听 并且监听listener 中实现的onTouch()的返回值
如果返回值为true表示事件被消费 事件结束 返回值为false表示事件未被消费继续执行
监听view 中onTouchEvent()方法中的返回值 返回值为true事件被消费事件结束 返回值为false标志着最终我们的事件没有被消费
验证事件整个分发流程事件没有被拦截且子view没有消费此事件
Activity dispatchTouchEvent()=======>ViewGroup dispatchTouchEvent()=======>ViewGroup onInterceptTouchEvent()没有拦截
=======>View dispatchTouchEvent()=======>View onTouchEvent()没有消费=======>ViewGroup onTouchEvent()没有消费=======>
Activity onTouchEvent()结束
并且如果是同一个事件序列 子View或ViewGroup没有消费该事件后续事件就不会再分发到子View中。就会出现如下结果:
Activity dispatchTouchEvent()=======>Activity onTouchEvent()结束