Android开发中,经常会遇到触摸事件冲突,比如ViewPager的轮播图跟Fragment的划动事件冲突,或者轮播图跟下拉事件冲突,自定义view的事件处理等,本文章将会详细介绍Activity、View、ViewGroup三者的触摸事件传递机制,传递包括三个阶段:分发、拦截、消费。
一.触摸事件的类型
触摸事件对应的是 MotionEvent 类,事件类型主要有三种:
ACTION_DOWN:用户按下操作,表示一次触摸事件的开始。
ACTION_MOVE:在按下的情况下,进行移动。轻微的移动都会传递到该事件。
ACTION_UP:用户手指离开屏幕,表示一次触摸事件的
注 :如果用户仅仅的是点击而已,则只会执行到 ACTION_DOWN 和 ACTION_UP 两个事件,不会执行到 ACTION_MOVE 事件。所以 ACTION_DOWN 和 ACTION_UP 是事件是必须的。
二.触摸事件的传递阶段
1.分发(Dispatch)
在Android系统中所有的触摸事件都是由 dispatchTouchEvent 方法进行分发的。该方法中判断事件是被消费(return true),还是继续分发给子视图处理(return super.dispatchTouchEvent),如果当前视图是ViewGroup或者其子类,则会调用onInterceptTouchEvent 判断是否截拦。
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
return super.dispatchTouchEvent(event);
}
2.截拦(Intercept)
事件的截拦 InterceptTouchEvent 只存在于ViewGroup及其子类,activity和View是不存在该方法。该方法判断事件是被截拦 (return true)并交给自身的 OnToucEvent 方法进行消费,还是继续传递给子视图(return super.InterceptTouchEvent 或者 return false)。
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return super.onInterceptTouchEvent(ev);
}
3.消费(Consume)
事件的消费通过 OnTouchEvent 方法判断,是被消费(return true),还是不处理(return false)并将事件传递给父视图的 OnTouchEvent 方法进行处理。
@Override
public boolean onTouchEvent(MotionEvent event) {
return super.onTouchEvent(event);
}
Android系统中,所有拥有事件传递能力的类有下面三种。
- Activity: 拥有dispatchTouchEvent 、OnTouchEvent
- ViewGroup: 拥有dispatchTouchEvent 、OnInterceptTouchEvent 、OnTouchEvent
- View:拥有dispatchTouchEvent 、OnTouchEvent
dispatchTouchEvent、onInterceptTouchEvent和onTouchEvent它们的关系可以用如下伪代码表示:
public boolean dispatchTouchEvent(MotionEvent ev) {
boolean consume = false;
if (onInterceptTouchEvent(ev)) {
consume = onTouchEvent(ev);
} else {
consume = child.dispatchTouchEvent(ev);
}
return consume;
}
点击事件的传递规则:对于一个根ViewGroup来说,点击事件产生后,首先会传递给它,这时它的dispatchTouchEvent就会被调用,如果这个ViewGroup的onInterceptTouchEvent方法返回true就表示它要拦截当前事件,接着事件就会交给这个ViewGroup处理,即它的onTouchEvent方法就会被调用;如果这个ViewGroup的onInterceptTouchEvent方法返回false就表示它不拦截当前事件,这时当前事件就会继续传递给它的子元素,接着子元素的dispatchTouchEvent方法就会被调用,如此反复直到事件被最终处理。
参考博客http://blog.csdn.net/awangyunke/article/details/22047987
Android系统中的每个View的子类都具有下面三个和TouchEvent处理密切相关的方法:
1)public boolean dispatchTouchEvent(MotionEvent ev) 这个方法用来分发TouchEvent,用来分发事件,如果拦截就交给onTouchEvent处理,否则传递给子view处理,拦截与否通过onInterceptTouchEvent的返回值来体现
2)public boolean onInterceptTouchEvent(MotionEvent ev) 这个方法用来拦截TouchEvent 返回true表示拦截,false表示不拦截
3)public boolean onTouchEvent(MotionEvent ev) 这个方法用来处理TouchEvent,处理触摸事件
当 TouchEvent发生时,首先Activity将TouchEvent事件通过dispatchTouchEvent方法传递给ViewGroup
注:以下所说的子view和父view均是包含关系,不是继承关系
1,ViewGroup通过dispatchTouchEvent方法传递给interceptTouchEvent:
(1)如果返回true ,则交给这个ViewGroup的onTouchEvent处理。
(2)如果返回false,则交给子View的 dispatchTouchEvent方法处理。
2,事件传递到子view 的 dispatchTouchEvent方法中,通过方法传递到当前View的onTouchEvent方法中:
(1)如果返回true,那么这个事件就会止于该view。
(2)如果返回 false ,那么这个事件会从这个子view 往上传递,而且都是传递到父View的onTouchEvent 来接收。
(3)如果传递到ViewGroup的 onTouchEvent 也返回 false 的话,则继续传递到Activity的onTouchEvent中,如果还是false,则这个事件就会“消失“;事件向上传递到中间的任何onTouchEvent方法中,如果返回true,则事件被消费掉,不会再传递
事件的分发机制如下图