- 1.View的事件分发
- 2.ViewGroup的事件分发
- 3.Activity的事件分发
在View的事件分发最后有个结论:在一个非容器类View的onTouchEvent()里面,如果一个view的clickable为false,down事件传递进来后,什么都不会执行,最后该view的onTouchEvent()会直接就返回false,而且这一个Touch事件系列中的后续move,up事件都不会传递到该view,直到下一个Touch事件系列到来(一个Touch事件系列会一般经历down---->move----->up)。
这个结论其实在View的事件分发相关方法dispatchTouchEvent()和onTouch()以及onTouchEvent()里面并没有体现,它的体现是在ViewGroup里面的dispatchTouchEvent()。一个onTouch事件从屏幕上产生,首先会经历Activity,然后会经历一系列的ViewGroup,最终才是到上篇分析的View(不是ViewGroup的View),由于ViewGroup的事件分发内容较多,本篇先学习Activity的事件分发源码
Activity的dispatchTouchEvent()源码:
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
//down事件会调用该方法
onUserInteraction();
}
if (getWindow().superDispatchTouchEvent(ev)) {
return true;
}
//上面第二个if如果走不进去调用onTonchEvent(),并返回其值
return onTouchEvent(ev);
}
onUserInteraction()方法:
public void onUserInteraction() {
}
该方法是空实现,如果我们在Activity里面想对down事件做些操作,可以重写这个方法。接下来看getWindow().superDispatchTouchEvent(ev)源码:
//Window类的方法,Window类是个抽象类
public abstract boolean superDispatchTouchEvent(MotionEvent event);
Window类是个抽象类,所以直接看调用者getWindow():
public Window getWindow() {
return mWindow;
}
mWindow是在Activity的attach()里面赋值的:
final void attach(Context context, ActivityThread aThread, Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor voiceInteractor,
Window window, ActivityConfigCallback activityConfigCallback) {
....省略代码
//给mWinddow赋值
mWindow = new PhoneWindow(this, window, activityConfigCallback);
mWindow.setWindowControllerCallback(this);
mWindow.setCallback(this);
.....省略代码
}
可以看到getWindow().superDispatchTouchEvent(ev)实际是调用PhoneWindow的superDispatchTouchEvent(ev)。phoneWindow的superDispatchTouchEvent()源码如下:
public boolean superDispatchTouchEvent(MotionEvent event) {
return mDecor.superDispatchTouchEvent(event);
}
最终是调用DecorView的superDispatchTouchEvent(event),DecorView是整个View树的根View,它是继承FrameLayout的,而FrameLayout又是继承ViewGroup的,所以事件分发从就从Activity传递到了ViewGroup的dispatchTouchEvent(),ViewGroup的dispatchTouchEvent()如果返回true,Activity的dispatchTouchEvent()就直接返回true.如果返回false就执行Activity的onTouchEvent(),并且返回onTouchEvent()的返回值
Activity的onTouchEvent()源码:
public boolean onTouchEvent(MotionEvent event) {
//Window类的方法
if (mWindow.shouldCloseOnTouch(this, event)) {
finish();
return true;
}
return false;
}
shouldCloseOnTouch()方法在Window类里面,PhoneWindow并没有重写,接着看shouldCloseOnTouch():
public boolean shouldCloseOnTouch(Context context, MotionEvent event) {
//判断mCloseOnTouchOutside 标记,是否是down事件,是否超出window边界,以及DecorView是否为空
if (mCloseOnTouchOutside && event.getAction() == MotionEvent.ACTION_DOWN
&& isOutOfBounds(context, event) && peekDecorView() != null) {
return true;
}
return false;
}
该方法主要判断Touch事件是否在window边界之外,所以这个if语句一般是走不进来,返回false。最终Activtiy的dispatchTouchEvent()的返回值和onTouchEvent()返回值一样返回false。
Activity的事件分发总结:
1,如果是down事件,会调用onUserInteraction(),move和up事件不会
2,事件传递到Activity后首先会去调用ViewGroup的dispatchTouchEvent(),如果ViewGroup的dispatchTouchEvent()返回true,Activity的dispatchTouchEvent()会直接返回true,如果ViewGroup的dispatchTouchEvent()返回false,会再去调用onTouchEvent(),这时候Activity的dispatchTouchEvent()返回值和onTouchEvent()一样