首先在写这篇博客的时候,我们先举个例子。在一个安卓的布局文件中,我们加一个textview。那么问题来啦,当TouchEvent发生时,是谁先接收这个事件呢,是Activity(虽然之前肯定是一系列的传感器,但与安卓相关时是Activity)然后我们解释一下事件分发的三个关键方法:
public boolean dispatchTouchEvent(MotionEvent ev)
它是View或ViewGroup处理事件分发的发起者,Activity接收到这个触控事件最先调起的就是这个方法,然后在判断是拦截还是分发事件给子容器。
public boolean onInterceptTouchEvent(MotionEvent ev)
ViewGroup专用,用来拦截事件,是处理事件冲突的最佳地点
public boolean onTouchEvent(MotionEvent event)
触控事件的真正处理者,最后每个事件都会在这里被处理
首先我们需要知道,触摸到任何一个控件 ,都会调用该控件的dispatchTouchEvent().具体的传递顺序可以看一下下面的伪代码。
public boolean dispatchTouchEvent(MotionEvent ev){
boolean isConsumed = false;
if(onInterceptTouchEvent(ev)){
isCousumed = this.onTouchEvent(ev);
}else{
isConsumed = childView.dispatchTouchEvent(ev);
}
return isConsumed;
}
再举个粟子
activity就好比我们的老板,viewgroup好比总经理 ,TextView好比员工。它们默认都是无法完成任务的。当老板布置一个任务分发下来的时候,总经理先执行它的拦截事件,并安排给员工做,那么就调用TextView的dispatchtouchEvent(),如果这件事情,员工能做(也就是开发者需要它完成),那么执行员工的ontouchEvent(),返回true。如果不能做,返回给viewgroup,这个时候,就需要总经理自己做,如果总经理能做,那么执行总经理 的ontouchEvent(),返回true。如果不能做,返回给activity。最后,如果开发者需要它拦截,就改为true,否则即为默认的false.
一句话就能概括,ViewGroup收到事件后调用dispatch,在dispatch中先检查是否要拦截,若拦截则ViewGroup吃掉事件,否则交给有处理能力的子容器处理。
另外补充一点:
从用户点击屏幕开始触发一个系列的点击事件时,事件真正的传递流程是:Activity(PhoneWindow)->DecorView->ViewGroup->View,在到达ViewGroup之前还有一个DecorView,事件是从Activity传过来的,但这些东西其实和ViewGroup的原理是一样的,Activity能看做一个大的ViewGroup,当它的DecorView包含的所有子View没有人能够消耗事件的时候(这样说并不严谨)最后还是会交给Activity处理。
再补充一点:
任何View只要拒绝了一系列事件中的ACTION_DOWN(返回false),则后续事件都不会再传递过来了。但如果拒绝了其他的事件,后续事件还是可以传过来的,比如View某次ACTION_MOVE没处理,这个没处理的事件最后会被Activity消耗掉(而不是View的父容器),但后续的事件还是会继续传给该View。
初出茅庐,请批评指教。并在此感谢指导我的老大!