注册

从伪代码理解View事件分发过程

事件从起源

从手指从屏幕按下的瞬间,触摸事件经过一系列处理会来到ActivitydispatchTouchEvent中。

Activity.java

public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
onUserInteraction();
}
//getWindow().superDispatchTouchEvent(ev) 返回true代表消费了事件
if (getWindow().superDispatchTouchEvent(ev)) {
return true;
}
//否则调用Activity的onTouchEvent
return onTouchEvent(ev);
}

getWindow()实际返回的是PhoneWindow

PhoneWindow.java

@Override
public boolean superDispatchTouchEvent(MotionEvent event) {
return mDecor.superDispatchTouchEvent(event);
}

getWindow().superDispatchTouchEvent(ev)实际会调用到mDecor.superDispatchTouchEvent(event)

DecorView.java

public class DecorView extends FrameLayout 
public boolean superDispatchTouchEvent(MotionEvent event) {
return super.dispatchTouchEvent(event);
}
}

跟踪DecorView会发现DecorView继承自FrameLayout,因为FrameLayout没有重写dispatchTouchEvent方法,所以事件从Activity一路下来,最终事件的入口是ViewGroupdispatchTouchEvent

开发中,事件一般通过层层ViewGroup传递到View中,进行消费。一般View做真正的事件消费。

View的事件分发

View.java--伪代码

/**
* view接收事件的入口,事件由ViewGroup分发过来
*/

public boolean dispatchTouchEvent(MotionEvent event) {
boolean result = false;

//如果设置了OnTouchListener,并且mOnTouchListener.onTouch返回了True,
//设置Result为True,那么代表事件到这已经消费完成了。
if (mOnTouchListener != null && mOnTouchListener.onTouch(this, event)) {
result = true;
}

//没有设置OnTouchListener,或者mOnTouchListener.onTouch返回了false时,result为false
//此时会回调View.onTouchEvent方法
if(!result&& onTouchEvent(event)){
result = true;
}
return result;
}

public boolean onTouchEvent(MotionEvent event) {
//如果设置了onClickListener,那么返回True代表事件到这已经消费完成了。
if (onClickListener != null) {
onClickListener.onClick(this);
return true;
}
return false;
}

dispatchTouchEvent是传入事件的入口,如果设置了mOnTouchListener,并且返回了true,那么dispatchTouchEvent就会返回true,代表事件被当前View消费了。如果没有设置,那么就会回调onTouchEvent方法,如果设置了onClickListener,那么onTouchEvent返回true,同理dispatchTouchEvent就会返回true,代表事件被当前View消费了.

从上面可以看出OnTouchListener先于onTouchEvent执行,onTouchEvent先于onClickListener执行。

ViewGroup的事件分发

ViewGroup.java--伪代码

    /**
* onInterceptTouchEvent 拦截事件
* @return true 代表拦截当前事件,那么事件就不会分发给ViewGroup的child View ,会调用自身的 super.dispatchTouchEvent(event)
* false 代表不拦截当前事件,不拦截事件,那么在dispatchTouchEvent会遍历child View,寻找能消费事件的child View
*/

public boolean onInterceptTouchEvent(MotionEvent ev) {
return false;
}

/**
* @param event 事件
* @param child 如果child 不为null,那么事件分发给它,否则,调用调用自身的 super.dispatchTouchEvent(event)
* @return 是否消费了该事件
*/

private boolean dispatchTransformedTouchEvent(MotionEvent event, View child) {
boolean handled = false;
if (child != null) {
handled = child.dispatchTouchEvent(event);
} else {
handled = super.dispatchTouchEvent(event);
}

return handled;
}


public boolean dispatchTouchEvent(MotionEvent event) {
boolean handled = false;
//是否拦截当前事件
boolean intercepted = onInterceptTouchEvent(event);
//触碰的对象
TouchTarget newTouchTarget = null;
int actionMasked = event.getActionMasked();

if (actionMasked != MotionEvent.ACTION_CANCEL && !intercepted) {
if (actionMasked == MotionEvent.ACTION_DOWN) {
//ViewGroup child View 数组
final View[] children = mChildren;
//倒序遍历,最后的通常是需要处理事件的
for (int i = children.length - 1; i >= 0; i--) {
View child = mChildren[i];
//isContainer 方法判断事件是否落在View中
if (!child.isContainer(event.getX(), event.getY())) {
continue;
}
//找到可以接收事件的View,把事件分发给他,
//如果dispatchTransformedTouchEvent返回了True代表消费了事件
if (dispatchTransformedTouchEvent(event, child)) {
handled = true;
//通过child包装成TouchTarget对象
newTouchTarget = addTouchTarget(child);
break;
}

}
}
}
//如果TouchTarget为null,那么事件就发就自己处理
//mFirstTouchTarget == null 在onInterceptTouchEvent返回true时,或没有找到可以消费的child View时成立
if (mFirstTouchTarget == null) {
handled = dispatchTransformedTouchEvent(event, null);
}
return handled;
}

dispatchTouchEvent是事件接收的入口,如果拦截事件,那么就调用super.dispatchTouchEvent(event),我们知道ViewGroup是继承View的,那么调用super.dispatchTouchEvent(event)等于调用ViewdispatchTouchEvent

View.java

/**
* view接收事件的入口,事件由ViewGroup分发过来
*/

public boolean dispatchTouchEvent(MotionEvent event) {
boolean result = false;

//如果设置了OnTouchListener,并且mOnTouchListener.onTouch返回了True,
//设置Result为True,那么代表事件到这已经消费完成了。
if (mOnTouchListener != null && mOnTouchListener.onTouch(this, event)) {
result = true;
}

//没有设置OnTouchListener,或者mOnTouchListener.onTouch返回了false时,result为false
//此时会回调View.onTouchEvent方法
if(!result&& onTouchEvent(event)){
result = true;
}
return result;
}

如果不拦截,那么就会遍历当前ViewGroupchild view,找能消费事件的View,如果找到,调用dispatchTransformedTouchEvent(event, child),这里的child可以是ViewGroup或者是View,最后根据dispatchTransformedTouchEvent返回值判断是否消费了事件,如果返回false后,那么调用ViewGroupsuper.dispatchTouchEvent(event)

0 个评论

要回复文章请先登录注册