一、基础知识储备
在Android开发中,事件分发机制是一块Android比较重要的知识体系,了解并熟悉整套的分发机制有助于更好的分析各种点击滑动失效问题,更好去扩展控件的事件功能和开发自定义控件,同时事件分发机制也是Android面试必问考点之一,如果你能把下面的一些事件分发图当场画出来肯定加分不少。废话不多说,总结一句:事件分发机制很重要,这部分知识涉及的仍然以View为主,这也是初级应用层Android开发者打交道最多的知识点。
二、前期基础知识普及
(1)Android事件分发的对象是谁?
解答:点击事件(Touch事件)。当用户触摸屏幕时(View 或 ViewGroup派生的控件),将产生点击事件(Touch事件)。常见的点击事件包括:单击、双击、触摸、滑动。
Touch事件的相关细节(发生触摸的位置、时间等)被封装成MotionEvent对象
MotionEvent事件类型:事件类型 具体动作
- MotionEvent.ACTION_DOWN 按下View(所有事件的开始)
- MotionEvent.ACTION_UP 抬起View(与DOWN对应)
- MotionEvent.ACTION_MOVE 滑动View
- MotionEvent.ACTION_CANCEL 结束事件(非人为原因)
事件列:从手指接触屏幕 至 手指离开屏幕,这个过程产生的一系列事件。当一个点击事件(MotionEvent )产生后,系统需把这个事件传递给一个具体的 View 去处理。
(2)Android事件分发机制的定义:将点击事件(MotionEvent)传递到某个具体的View & 处理的整个过程。
即Android事件分发过程 = Android事件传递过程
(3)Android事件在哪些对象中传递:
解答:Activity、ViewGroup、View。
传递顺序固定为:Activity -> ViewGroup -> View
(4)事件分发过程中涉及到的方法有哪些?
dispatchTouchEvent() 、onInterceptTouchEvent()和onTouchEvent();
Dispatch—英文:派遣;intercept—英文:拦截
(5)小结:所有理论概念,如下图所示
三、Android事件分发机制具体实现方式
要充分了解Android事件分发机制,那么本质上是要理解:
- Activity对点击事件的分发机制
- ViewGroup对点击事件的分发机制
- View对点击事件的分发机制
(1)Activity对点击事件的分发机制图:
(2)ViewGroup事件的分发机制图
(3)View事件的分发机制图
小结:看完上面三幅图,对Android事件分发机制就有了基础的了解,下面我们对整个事件分发的工作流程进行梳理。
(4)工作流程总结图(注:消费代表完成事件分发,事件分发事件结束)
(5)分发核心方法总结图
四、示例—APP界面举例介绍,看完就懂了
如上图所示,1个Activity,1个ViewGroup,7个View(很常见的ListVew界面或者按钮控制的设置界面)。
用户点击了黄色的按钮——产生了点击事件,那么此次事件如何分发?分为两种情况:(1)紫色按钮;(2)黄色按钮
(1)用户点击黄色按钮之后,紫色按钮View发生的事件——默认情况
①Activity层面,调用dispatchTouchEvent()方法,结果:Activity层面没有对事件进行消费,事件分发没有停止,然后Activity会把事件往下分发至ViewGroup;
②ViewGroup层面,调用ViewGroup的dispatchTouchEvent()方法和onInterceptTouchEvent()方法,进行处理。结果:ViewGroup层面没有拦截Activity分发下来的事件,继续把事件往下分发到紫色的View层面;
③View层面,调用View的dispatchTouchEvent()接收到分发下来的事件,开始利用onTouchEvent()方法对事件进行处理。结果:紫色的view发现自己处理不了这个分发事件,然后向上层ViewGroup反馈,ViewGroup调用自己的onTouchEvent()方法后发现自己也处理不了,然后又向上层Activity反馈,Activity调用自己的onTouchEvent()方法后,最终发现自己依旧处理不了,最后就把点击事件无处理暴露出去。
(2)用户点击黄色按钮之后,黄色按钮View发生的事件——处理事件
①Activity层面,调用dispatchTouchEvent()方法,结果:Activity层面没有对事件进行消费,事件分发没有停止,然后Activity会把事件往下分发至ViewGroup;(与紫色按钮Activity层面的相同)
②ViewGroup层面,调用ViewGroup的dispatchTouchEvent()方法和onInterceptTouchEvent()方法,进行处理。结果:ViewGroup层面没有拦截Activity分发下来的事件,继续把事件往下分发到紫色的View层面;(......相同)
③View层面,调用View的dispatchTouchEvent()接收到分发下来的事件,开始利用onTouchEvent()方法对事件进行处理(最常见的方式就是设置Button按钮来响应点击事件)。onTouchEvent()方法返回值为true,到此事件分发结束,处理结果逐层往上返回,最终完成了用户的点击事件。
举例说明——自定义一个不能滑动的ViewPager
不可滑动,不代表真的禁止滑动,而是要让其接收不到手指的触摸事件,这样就无从触发滑动的方法:
@Override
public boolean onInterceptTouchEvent (MotionEvent ev) {
// 不拦截这个事件
return false;
}
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouchEvent (MotionEvent ev) {
// 不处理这个事件
return false;
}
ViewPager继承自ViewGroup,肯定拦截了滑动事件和处理了事件,这里覆写之后,对滑动事件不予处理。最终达到禁止滑动的目的!