触屏是用户和手机交互的基础,手指触屏时产生一系列事件,控制视图改变,在树形视图中,事件从顶层向下传递。
从根结点顶层视图DecorView的dispatchPointerEvent方法开始,它调用基类View的dispatchPointerEvent方法。
public final boolean dispatchPointerEvent(MotionEvent event) {
if (event.isTouchEvent()) {//判断属于Touch类型
return dispatchTouchEvent(event);
} else {
return dispatchGenericMotionEvent(event);
}
}
判断触屏类型,然后,调用dispatchTouchEvent方法,DecorView类重写该方法。
public boolean dispatchTouchEvent(MotionEvent ev) {
final Callback cb = getCallback();
return cb != null && !isDestroyed() && mFeatureId < 0
? cb.dispatchTouchEvent(ev): super.dispatchTouchEvent(ev);
}
PhoneWindow窗体对象,setCallback(this)方法初始化内部Callback,Activity类实现Callback接口,Window#Callback接口的dispatchTouchEvent方法。
DecorView类是PhoneWindow内部类,获取PhoneWindow内部Callback对象,即Activity,事件优先派发到Activity。
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
onUserInteraction();
}
//窗体视图成功消费
if (getWindow().superDispatchTouchEvent(ev)) {
return true;
}
//窗体视图未成功时,由Activity处理。
return onTouchEvent(ev);
}
在Activity再将事件交给窗体,由窗体向视图派发。视图中派发失败,未消费,最后由Activity的onTouchEvent方法兜底。
Window窗体的superDispatchTouchEvent方法。
@Override
public boolean superDispatchTouchEvent(MotionEvent event){
return mDecor.superDispatchTouchEvent(event);
}
顶层视图DecorView的superDispatchTouchEvent方法。
public boolean superDispatchTouchEvent(MotionEvent event) {
//正式进入顶层视图派发。
return super.dispatchTouchEvent(event);
}
最终,进入DecorView父类ViewGroup的dispatchTouchEvent方法,在树结构中开始传递。
总结
视图触屏事件入口是dispatchTouchEvent方法。DecorView重写该方法,让事件通过Activity实现的一个接口,流向Activity,基类View和ViewGroup都实现该方法。
Activity希望控制事件传递,实现Window暴露的Callback接口,DecorView是PhoneWindow内部类,而Window会设置这个接口被DecorView获取,经过Activiity拦截,然后再进入Window,传递到视图,所有视图均不消费时,Activity增加一层亲自处理的兜底逻辑,交给Activity的onTouchEvent处理。
任重而道远