概述
一圖勝千言:
Activity對(duì)觸摸事件的分發(fā)
- 我們首先來(lái)看一下Activity是如何分發(fā)觸摸事件的:
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
onUserInteraction();
}
if (getWindow().superDispatchTouchEvent(ev)) {//將事件傳遞給和該Activity組合的Window對(duì)象吮炕。
return true;
}
return onTouchEvent(ev);
}
可以看到,事件被傳遞給了和Activity對(duì)應(yīng)的Window對(duì)象。通過(guò)查看Window源碼我們知道姑廉,Window是一個(gè)虛擬類。Window的累注釋中明確說(shuō)明目前只有一個(gè)實(shí)現(xiàn)類叫做PhoneWindow。
- 我們來(lái)看一下PhoneWindow是如何傳遞觸摸事件的:
@Override
public boolean superDispatchTouchEvent(MotionEvent event) {
return mDecor.superDispatchTouchEvent(event);
}
可以看到事件被傳遞給了Activity的DecorView热某。我們知道菩鲜,DecorView是Activity的頂級(jí)視圖园细。他是PhoneWindow的一個(gè)內(nèi)部類。
- DecorView對(duì)事件的傳遞接校。
private final class DecorView extends FrameLayout implements RootViewSurfaceTaker {
public boolean superDispatchTouchEvent(MotionEvent event) {
return super.dispatchTouchEvent(event);
}
}
我們看到猛频,DecorView的superDispatchTouchEvent方法調(diào)用了父類的dispatchTouchEvent(event)方法。而DecorView是繼承自FrameLayout的蛛勉。FrameLayout繼承自ViewGroup并且沒(méi)有重寫dispatchTouchEvent(event)方法鹿寻。
至此,觸摸事件已經(jīng)從Activity傳遞到了和該Activity對(duì)應(yīng)的ViewTree的頂級(jí)ViewGroup中诽凌。
事件在ViewGroup中的分發(fā)過(guò)程毡熏,我們將在后續(xù)文章中詳細(xì)分析。這里重點(diǎn)需要了解:Activity在通過(guò)dispatchTouchEvent()傳遞觸摸事件的時(shí)候皿淋,會(huì)調(diào)用到ViewGroup的dispatchTouchEvent()招刹。從而實(shí)現(xiàn),將Activity中的觸摸事件傳遞給它所包含的View或ViewGroup窝趣。
Activity對(duì)觸摸事件的處理
回顧一下Activity的dispatchTouchEvent()方法的源碼:
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
onUserInteraction();
}
if (getWindow().superDispatchTouchEvent(ev)) {//將事件傳遞給和該Activity組合的Window對(duì)象疯暑。
return true;
}
// 如果superDispatchTouchEvent()返回false。
// 即Activity的根視圖以及根視圖的子視圖都沒(méi)有處理該事件的話哑舒,則調(diào)用Activity的onTouchEvent()
return onTouchEvent(ev);
}
上面小節(jié)描述的情況是getWindow().superDispatchTouchEvent(ev)中一級(jí)一級(jí)向下傳遞的情況妇拯。那么如果getWindow().superDispatchTouchEvent(ev)調(diào)用完成返回false,即即Activity的根視圖以及根視圖的子視圖都沒(méi)有處理該事件的話洗鸵,則調(diào)用Activity的onTouchEvent()越锈,由Activity中的onTouchEvent做出最后的處理。
我們看一下Activity的onTouchEvent()的代碼:
public boolean onTouchEvent(MotionEvent event) {
if (mWindow.shouldCloseOnTouch(this, event)) {
finish();
return true;
}
return false;
}
可以看到膘滨,Activity中默認(rèn)的onTouchEvent方法很簡(jiǎn)單:
只處理一種情況:當(dāng)mWindow.shouldCloseOnTouch(this, event)返回true時(shí)調(diào)用finish()方法結(jié)束Activity甘凭。其他情況一律不處理。那么mWindow.shouldCloseOnTouch(this, event)在哪種情況下返回true就顯得非常重要火邓。我們來(lái)看下Window類中shouldCloseOnTouch()方法的的源碼:
public boolean shouldCloseOnTouch(Context context, MotionEvent event) {
if (mCloseOnTouchOutside && event.getAction() == MotionEvent.ACTION_DOWN
&& isOutOfBounds(context, event) && peekDecorView() != null) {
return true;
}
return false;
}
- mCloseOnTouchOutside是一個(gè)boolean變量丹弱,它是由Window的android:windowCloseOnTouchOutside屬性值決定。
- isOutOfBounds(context, event)是判斷該event的坐標(biāo)是否在context(對(duì)于本文來(lái)說(shuō)就是當(dāng)前的Activity)之外铲咨。是的話躲胳,返回true;否則纤勒,返回false坯苹。
- peekDecorView()則是返回PhoneWindow的mDecor。
也就是說(shuō)摇天,如果設(shè)置了android:windowCloseOnTouchOutside屬性為true粹湃,并且當(dāng)前事件是ACTION_DOWN恐仑,而且點(diǎn)擊發(fā)生在Activity之外,同時(shí)Activity還包含視圖的話再芋,則返回true菊霜;表示該點(diǎn)擊事件會(huì)導(dǎo)致Activity的結(jié)束。
比較典型的情況就是dialog形的Activity济赎。
下一篇我們將分析事件在ViewTree中的傳遞過(guò)程鉴逞。
參考文獻(xiàn)
http://wangkuiwu.github.io/2015/01/02/TouchEvent-Activity/
http://blog.csdn.net/yanbober/article/details/45932123
http://blog.csdn.net/ns_code/article/details/49848801