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

Android 事件分发细说

2016-06-06 11:54 519 查看
一直以来都对Android 的事件分发机制有疑惑,以前只知道事件分发涉及到三个方法:
dispatchTouchEvent
onInterceptTouchEvent
onTouchEvent
。三个方法分别为分发事件,拦截事件,处理事件,对于这些知识一知半解,并没有深入了解。当遇到滑动冲突的时候就在父View或者子View的这三个方法,
return true or false
,一个个试(笨~)。上网看别人的博客,篇幅太长并且看得我一愣一愣的,我有点方。今天终于理解的比较完整了,我尝试以一种直观简单的方法描述这里面的流程。

首先也是这3个方法:

dispatchTouchEvent
,事件的分发,事件传到当前
View
的话一定会调用,内部调用了
onInterceptTouchEvent
onTouchEvent
,返回结果表示是否消耗当前事件,不消耗就向上层传递。

onInterceptTouchEvent
,用来判断是否拦截某个事件。

onTouchEvent
,用来判断是否消耗事件。

可能看了上面3个方法有点懵逼。这里一个一个的解释。

dispatchTouchEvent
的内部实现伪代码简化之后是这样的。

@Override
public boolean dispatchTouchEvent(MotionEvent e){
boolean consume = false;
if(onInterceptTouchEvent(e)){
comsume = onTouchEvent(e);
}else{
consume = child.dispatchTouchEvent(e);
}
return consume;
}


上面的代码简单粗暴有木有?上面的代码把机制展现得淋漓尽致了。

首先调用
onInterceptTouchEvent
询问是否拦截,如果拦截,就由
onTouchEvent
处理,否则
else
就由
childView
dispatchTouchEvent
决定。

假设我们有以下场景。有一个
Activity
,然后里面嵌套了2个
View
,一个是
ParentView
,一个是
ChildView
。那么事件的传递是怎么样的呢。

事件的传递顺序是这样的:
Activity -> Window -> View
,假设我的
ParentView
得到事件之后,
ParentView#dispatchTouchEvent
来进行判断。然后调用了
ParentView#onInterceptTouchEvent
,如果
ParentView#onInterceptTouchEvent
返回
true
,就会调用
ParentView#onTouchEvent
。如果返回了
false
就会调用
ChildView#dispatchTouchEvent
,然后重复上面的过程。

这样很好理解,假设我在ParentView和ChildView的3个方法都没有做处理的话,事件的传递过程就是:

ParentView -> dispatchTouchEvent


ParentView -> onInterceptTouchEvent ->return false


ChildView -> dispatchTouchEvent


ChildView -> onInterceptTouchEvent


ChildView ->onTouchEvent


ParentView ->onTouchEvent


Activity -> onTouchEvent


还不够清楚?如下图:



只要明白了以上的原理,就能根据不同的业务需求进行拦截等相关操作了。

最后有一些小知识点需要注意的:

如果
View
设置了
onTouchListener
,会先执行
OnTouchListener
onTouch
方法。如果该方法返回
true
,表示消费了。不会执行
onTouchEvent了
,如果
onTouch
返回
false
,就会继续执行
onTouchEvent


如果
View
设置了
OnClickListener
的话,会在
onTouchEvent
中调用
listener.onClick(this);


有一种场景,如果一个
ViewGroup
和它的
childView
都在
onTouchEvent
返回了
false
,根据上面的
dispathchTouchEvent
分发机制,事件会传到
ViewGroup
onTouchEvent
,如果
ViewGroup
onTouchEvent
也返回了
false
的话,就会返回到
Activity
Activity
onTouchEvent
就会被调用。

结论

一个事件的序列是从手指按下到手指抬起的整个过程,中间会有
ACTION_DOWN
,
ACTION_MOVE
,
ACTION_UP
的过程

一个事件如果某个
View
拦截了,那么这个
View
会处理整个事件序列。

如果
View
决定拦截某个事件的话,就会交给
onTouchEvent
处理,在一个事件序列中不会再调用
onInterceptTouchEvent


如果一个
View
的决定拦截某个事件
(onInterceptTouchEvent return true)
,则在处理
ACTION_DOWN
的时候,如果返回
false
,表示他不处理这个事件,这时候
dispatchTouchEvent
就会返回
false
,那么后续事件就会交给上层
View
处理,就不会再调用这个
View
onTouchEvent
了。也就是说后续的
ACTION_MOVE
ACTION_UP
都不会调用它的
TouchEvent
了,都交由父级
View
来处理。

View
onTouchEvent
默认返回
true
View
longClickable
clickable
都为
false
的时候就会返回
true


childView
可以通过
requestDisallowInterceptTouchEvent()
方法请求阻止或运行父
View
的事件分发过程。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: