Android(触摸屏)中应用程序与用户交互用的就是touch事件来完成的,一个界面上的控件会有很多,那么
一个touch事件是如何传递的呢?
一、简介
Android中的touch事件都是以down(按下)事件开始,up(抬起)事件结束的
事件类型有:ACTION_DOWN(按下)、ACTION_UP(抬起)、ACTION_MOVE(移动)
ACTION_POINT_DOWN(多个手指按下)、ACTION_POINT_UP(多个手指抬起)
二、事件分发
Android中的View分为两个,一类是ViewGroup(含有子类View);一类是View(没有子类View),两类的
事件分发机制有所不同
1.View
有两个控件TextView和Button,分别点击一次,并且打印响应的信息(onTouch默认返回为false)
单击一次有两个事件响应:down和up分别执行一次,首先down事件执行如下
button.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
System.out.println("button");
return false;
}
});
textView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
System.out.println("textView");
return false;
}
});
分别点击一次后打印出来的效果如下
为什么点击两个控件最后打印出信息的数量是不同的呢,那我们首先要从TextView和Button的不同
入手,TextView默认是不可点击的,Button是可以点击的,然后带着这两点不同,看看系统的源码有
一下重大的发现呢!!
①button和textView都是View的子类,通过setOnTouchListener把OnTouchListener对象传到View
public boolean dispatchTouchEvent(MotionEvent event) {
....
//mOnTouchListener不为空,并且当前控件可用,onTouch方法对应得返回值
if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED &&
mOnTouchListener.onTouch(this, event)) {
return true;
}
//如果if对于逻辑不成立,调用onTouchEvent
//onTouch先于onTouchEvent,并且觉得当前onTouchEvent是否调用
return onTouchEvent(event);
}
②两个子View的onTouch返回值都为false,那么会执行本View的onTouchEvent(Event);
③View的onTouchEvent()方法执行如下
public boolean onTouchEvent(MotionEvent event) {
....
//判断当前控件是否有点击事件,如果有则执行if中逻辑,如果没有则不执行返回false
if (((viewFlags & CLICKABLE) == CLICKABLE ||
(viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) {
switch (event.getAction()) {
//点击事件触发点
case MotionEvent.ACTION_UP:
...
performClick();
...
}
//此处返回true则说明onTouchEvent,说明dispatchTouchEvent返回true,则响应所有事件
return true;
}
//此处返回false,等同于onTouchEvent,dispatchTouchEvent返回false,不响应所有事件
return false;
}
TextView不可点击,那么直接返回false,表示事件没有被消耗,那么down事件没有被消耗,up事
件也不会继续执行,所以textView只输出了一次结果
Button可以默认可被点击,那么会继续执行if语句中的内容,继而回响应up事件,所以会输出两次
结果
④如果给TextView设置一个点击事件的监听,那么也会输出两次结果,这是为什么呢?因为在监听
事件的源码中有如下的一段代码
public void setOnClickListener(OnClickListener l) {
//如果当前控件没有点击事件,设置一个点击事件
if (!isClickable()) {
setClickable(true);
}
mOnClickListener = l;
}
就算TextView不可点击,系统也会给它设置为可点击的,那么他就可以和Button一样了
2.ViewGroup
ViewGroup中事件分发和View有点不同,因为ViewGroup有子View,这就会有事件的分发或者拦截了
每个ViewGroup都有以下三个方法
dispatchTouchEvent(); 负责事件的分发
onInterceptTouchEvent();负责事件的拦截
onTouchEvent(); 负责响应事件
ViewGroup布局如下图
首先是down事件的分发
ViewGroup①在分发事件之前会调用自己的onInterceptTouchEvent()方法判断是否拦截,如果返
回false(不拦截),那么分发给ViewGroup②的dispatchTouchEvent事件,它在分发之前也会判断自己
是否要拦截,如果不拦截,那么传递给子View③,这时③不能再向下分发啦,需要判断onTouchEvent
是否消耗该down事件,如果返回为True(不消耗),继续向上返回给②的onTouchEvent,依次类推
在分发的过程中如果ViewGroup把事件拦截或者消耗掉了down事件,那么后续的move,up等事件会直
接传递给它不会再走判断的流程
三、小结
以上是对Android事件的简单理解,其实我们在用手机的时候主要就是在touch手机屏幕,对touch的
原理搞明白了,那么对于view是否该获得事件,以及viewGroup是否该拦截事件都会非常清楚