今天主要是讲Android的事件传递机制,在Android系统中事件传递机制分为两种,一种是ViewGroup和View两种;而修改事件传递的方向又分为两种,一种是:从ViewGroup到View的方向(这种是顺方向),另一种是从View逆修改ViewGroup的方向。本例子主要是讲解一个ViewGroup和一个View的情况。
Android系统中事件机制
区分ViewGroup和View的事件传递的区别,在ViewGroup中事件传递设计三个方法,而View只设计到两个。
- ViewGroup涉及的三个方法
- dispatchTouchEvent
- onInterceptTouchEvent
- onTouchEvent
- View涉及的两个方法
- dispatchTouchEvent
- onTouchEvent
从ViewGroup到View的事件传递过程
这张图是在我两年前学android的时候一个大神描述的,此图是我自己重新绘制的。有人问为什么事件传递是从Activity开始的,这里不深入了解底层,其实在Activity的onCreate方法里面setContentView方法我们把View依附给系统的Activity的时候,其实这个View依附在Activity的DecorView上面,所以这个是系统的View同样只有dispatchTouchEvent和onInterceptTouchEvent这两种方法。
现在我们不关心Activity里面事件机制,只关心Out、Middle、Center这三个,他们现在都要三个方法,表示他们都是ViewGroup,这里我们简单的描述一下三个方法。
dispatchTouchEvent:事件分发(true:不分发,false:分发下去)
onInterceptTouchEvent:事件拦截(true:拦截,false:不拦截)
onTouchEvent:事件处理(true:处理,false:不处理)
重点一:以上任何一个方法返回true都会表示箭头传递方向中断,用心的人会发现,假如我在dispatchTouchEvent哪里就返回为true呢?是的很多人没有考虑这个问题,假如我们在Out这个ViewGroup返回true,表示事件不会往下传递下去了,也就是说事件就在这里终止掉了,所有onTouchEvent事件我们都没法处理了。所以为什么自定义View的时候我们一般不回去处理dispatchTouchEvent这个方法。
重点二:假若我们在onInterceptTouchEvent这个方法返回true呢?表示事件拦截掉了不会重复执行onInterceptTouchEvent这个方法了。很多人不明白什么叫不会重复执行onInterceptTouchEvent,假若你尝试返回false(Middle ViewGroup dispatchTouchEvent返回为true的时候),你会发现onInterceptTouchEvent被多次执行了。
View修改ViewGroup的事件传递方向
/**
* 事件分发, 请求父控件是否拦截事件
* 1. 右划, 而且是第一个页面, 需要父控件拦截
* 2. 左划, 而且是最后一个页面, 需要父控件拦截
* 3. 上下滑动, 需要父控件拦截
*/
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
getParent().requestDisallowInterceptTouchEvent(true);// 不要拦截,
startX = (int) ev.getRawX();
startY = (int) ev.getRawY();
break;
case MotionEvent.ACTION_MOVE:
int endX = (int) ev.getRawX();
int endY = (int) ev.getRawY();
if (Math.abs(endX - startX) > Math.abs(endY - startY)) {// 左右滑动
if (endX > startX) {// 左划
if (getCurrentItem() == 0) {// 第一个页面, 需要父控件拦截
getParent().requestDisallowInterceptTouchEvent(false);
}
} else {// 右划
// 最后一个页面 需要拦截
if (getCurrentItem() == getAdapter().getCount() - 1) { getParent().requestDisallowInterceptTouchEvent(false);
}
}
} else {// 上下滑动
getParent().requestDisallowInterceptTouchEvent(false);
}
break;
}
return super.dispatchTouchEvent(ev);
}
以上是一个很典型的例子,就是在子View的dispatchTouchEvent方法里面通过getParent().requestDisallowInterceptTouchEvent这个方法就可以从子View那里修改父View的传递方向。
谢谢收看!小弟第一次写博客,以前是伸手党,若有不对的地方还请大家多多指导。