您的位置:首页 > 移动开发 > Android开发

Touch事件分发机制(相对于原版有修改)

2016-04-28 17:21 369 查看

Touch事件分发中的角色

Touch事件分发中有两个主角:ViewGroup和View。

Activity的Touch事件事实上是调用它内部的ViewGroup的Touch事件,可以直接当成ViewGroup处理。


View在ViewGroup内,ViewGroup也可以在其他ViewGroup内,这时候把内部的ViewGroup当成View来分析

ViewGroup与View的相关事件:

ViewGroup的相关事件有三个:

onInterceptTouchEvent

dispatchTouchEvent

onTouchEvent

View的相关事件只有两个:

dispatchTouchEvent

onTouchEvent。

ViewGroup的处理流程的树形结构模型:

ViewGroup和View组成了一棵树形结构,最顶层为Activity的ViewGroup,下面有若干的ViewGroup节点,每个节点之下又有若干的ViewGroup节点或者View节点,依次类推。如图:



当触摸发生时,由上至下传递。

下发的过程是:

调用**子View(ViewGroup)**的dispatchTouchEvent方法实现的1


上述例子中的消息下发顺序是这样的:①-②-⑤-⑥-⑦-③-④。

dispatchTouchEvent方法只负责事件的分发,它拥有boolean类型的返回值,当返回为true时,顺序下发会中断。在上述例子中如果⑤的dispatchTouchEvent返回结果为true,那么⑥-⑦-③-④将都接收不到本次Touch事件。

来个简单版的代码加深理解:

/**
* ViewGroup
* @param ev
* @return
*/
public boolean dispatchTouchEvent(MotionEvent ev){
....//其他处理,在此不管
View[] views=getChildView();
for(int i=0;i<views.length;i++){
//判断下Touch到屏幕上的点在该子View上面
if(...){
if(views[i].dispatchTouchEvent(ev))
return true;
}
}
...//其他处理,在此不管
}
/**
* View
* @param ev
* @return
*/
public boolean dispatchTouchEvent(MotionEvent ev){
....//其他处理,在此不管
return false;
}


在此可以看出,ViewGroup的dispatchTouchEvent是真正在执行“分发”工作,而View的dispatchTouchEvent方法,并不执行向下分发工作。

事实上子ViewdispatchTouchEvent方法真正执行的代码是这样的

/**
* View
* @param ev
* @return
*/
public boolean dispatchTouchEvent(MotionEvent ev){
....//其他处理,在此不管
return onTouchEvent(event);
}


子View的dispatchTouchEvent只是决定是否把touch事件交给自己处理,而处理的方法,便是onTouchEvent事件。

所以,一般情况下,我们不该在普通View内重写dispatchTouchEvent方法,因为它并不执行分发逻辑。当Touch事件到达View时,我们该做的就是是否在onTouchEvent事件中处理它。

ViewGroup的onTouchEvent事件是什么时候处理的呢?

当ViewGroup所有的子View都返回false时,onTouchEvent事件便会执行。由于ViewGroup是继承于View的,它其实也是通过调用View的dispatchTouchEvent方法来执行onTouchEvent事件(可以看Android源码)。

Aciton_UP和Action_MOVE什么时候执行?

当某个View或者ViewGroup的onTouchEvent事件返回true时,便表示它是真正要处理这次请求的View,之后的Aciton_UP和Action_MOVE将由它处理。当所有子View的onTouchEvent都返回false时,这次的Touch请求就由根ViewGroup,即Activity自己处理了。

看看改进后的ViewGroup的dispatchTouchEvent方法

View mTarget=null;//保存捕获Touch事件处理的View
public boolean dispatchTouchEvent(MotionEvent ev) {

//....其他处理,在此不管

if(ev.getAction()==KeyEvent.ACTION_DOWN){
//每次Down事件,都置为Null

if(!onInterceptTouchEvent()){
mTarget=null;
View[] views=getChildView();
for(int i=0;i<views.length;i++){
if(views[i].dispatchTouchEvent(ev))
mTarget=views[i];
return true;
}
}
}
//当子View没有捕获down事件时,ViewGroup自身处理。这里处理的Touch事件包含Down、Up和Move
if(mTarget==null){
return super.dispatchTouchEvent(ev);
}
//...其他处理,在此不管
if(onInterceptTouchEvent()){
//...其他处理,在此不管
}
//这一步在Action_Down中是不会执行到的,只有Move和UP才会执行到。
return mTarget.dispatchTouchEvent(ev);

}


ViewGroup还有个onInterceptTouchEvent,看名字便知道这是个拦截事件。这个拦截事件需要分两种情况来说明:

1当mTarge一直为null,该ViewGroup的onTouchEvent事件被执行。这种情况下可以把这个ViewGroup直接当成View来对待。

比如:.假如我们在某个ViewGroup的onInterceptTouchEvent中,将Action为Down的Touch事件返回true,那便表示将该ViewGroup的所有下发操作拦截掉,这种情况下,mTarget会一直为null,因为mTarget是在Down事件中赋值的。

另外,上文所列出的代码并非真正的源码,只是概括了源码在事件分发处理中的核心处理流程,真正源码各位可以自己去看,包含了更丰富的内容。


###补充:

“触摸事件由Action_Down、Action_Move、Aciton_UP组成,其中一次完整的触摸事件中,Down和Up都只有一个,Move有若干个,可以为0个。”,这里补充下其实UP事件是可能为0个的。

转载:http://www.cnblogs.com/linjzong/p/4191891.html
简单来说,就是ViewGroup遍历它包含着的子View,调用每个View的dispatchTouchEvent方法,而当子View为ViewGroup时,又会通过调用ViwGroup的dispatchTouchEvent方法继续调用其内部的View的dispatchTouchEvent方法。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Android touch