掃二維碼與項(xiàng)目經(jīng)理溝通
我們?cè)谖⑿派?4小時(shí)期待你的聲音
解答本文疑問(wèn)/技術(shù)咨詢/運(yùn)營(yíng)咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流
Android事件分發(fā)是指在Android系統(tǒng)中,當(dāng)用戶觸摸屏幕或執(zhí)行其他操作時(shí),系統(tǒng)如何將這些事件傳遞給正確的視圖或組件進(jìn)行處理的過(guò)程。

創(chuàng)新互聯(lián)-專業(yè)網(wǎng)站定制、快速模板網(wǎng)站建設(shè)、高性價(jià)比新洲網(wǎng)站開(kāi)發(fā)、企業(yè)建站全套包干低至880元,成熟完善的模板庫(kù),直接使用。一站式新洲網(wǎng)站制作公司更省心,省錢,快速模板網(wǎng)站建設(shè)找我們,業(yè)務(wù)覆蓋新洲地區(qū)。費(fèi)用合理售后完善,十年實(shí)體公司更值得信賴。
Android事件分發(fā)遵循一種稱為"事件分發(fā)機(jī)制"的規(guī)則,該機(jī)制由三個(gè)主要的階段組成:觸摸事件的捕獲階段、目標(biāo)視圖的處理階段和冒泡階段。
在觸摸事件的捕獲階段,事件從頂層視圖(如Activity)開(kāi)始,逐級(jí)向下傳遞,直到找到最底層的子視圖。在這個(gè)過(guò)程中,每個(gè)視圖都有機(jī)會(huì)攔截事件,如果某個(gè)視圖攔截了事件,則后續(xù)的視圖將無(wú)法接收到該事件。
在目標(biāo)視圖的處理階段,事件被傳遞給最底層的子視圖,并由該視圖進(jìn)行處理。如果該視圖沒(méi)有處理事件,則事件將被傳遞給其父視圖,直到找到能夠處理事件的視圖為止。
在冒泡階段,事件從底層視圖向上冒泡,直到達(dá)到頂層視圖。在這個(gè)過(guò)程中,每個(gè)視圖都有機(jī)會(huì)處理事件,如果某個(gè)視圖處理了事件,則后續(xù)的視圖將無(wú)法接收到該事件。
通過(guò)這種事件分發(fā)機(jī)制,Android系統(tǒng)能夠準(zhǔn)確地將用戶的操作傳遞給正確的視圖或組件進(jìn)行處理,從而實(shí)現(xiàn)了用戶與應(yīng)用程序的交互。在實(shí)際開(kāi)發(fā)中,我們可以通過(guò)重寫視圖的相關(guān)方法(如onTouchEvent())來(lái)自定義事件的處理邏輯,以滿足特定的需求。
以上是事件分發(fā)中的一些關(guān)鍵對(duì)象,它們共同協(xié)作,實(shí)現(xiàn)了Android中的事件分發(fā)機(jī)制。
MotionEvent是Android中的一個(gè)類,用于處理與用戶交互相關(guān)的事件,例如觸摸屏幕、按下按鈕等。它包含了一系列的常量和方法,用于獲取事件的類型、坐標(biāo)、時(shí)間等信息。通過(guò)監(jiān)聽(tīng)MotionEvent,開(kāi)發(fā)者可以實(shí)現(xiàn)對(duì)用戶的觸摸操作進(jìn)行響應(yīng)和處理。
以下是一些常用的MotionEvent方法:
這些方法可以幫助開(kāi)發(fā)者獲取觸摸事件的相關(guān)信息,并進(jìn)行相應(yīng)的處理。
MotionEvent#getAction()方法返回一個(gè)整數(shù),表示當(dāng)前觸摸事件的類型。具體的類型有以下幾種:
這些類型可以通過(guò)與MotionEvent類中定義的常量進(jìn)行比較來(lái)判斷當(dāng)前觸摸事件的類型。例如,可以使用以下代碼來(lái)判斷當(dāng)前事件是否為按下事件:
if (event.getAction() == MotionEvent.ACTION_DOWN) {
// 處理按下事件的邏輯
}示例:手指觸摸屏幕到離開(kāi)屏幕事件走向
圖片
在Android中,事件分發(fā)是通過(guò)View的事件分發(fā)機(jī)制來(lái)實(shí)現(xiàn)的。當(dāng)用戶觸摸屏幕或者進(jìn)行其他操作時(shí),事件會(huì)從頂層的ViewGroup開(kāi)始向下傳遞,直到找到合適的View來(lái)處理該事件。
Android中的事件分發(fā)涉及到以下幾個(gè)對(duì)象:
在事件分發(fā)過(guò)程中,每個(gè)對(duì)象都有機(jī)會(huì)處理事件。如果一個(gè)對(duì)象處理了事件,那么事件就會(huì)停止傳遞。如果一個(gè)對(duì)象沒(méi)有處理事件,那么事件會(huì)繼續(xù)向下傳遞,直到找到合適的處理者或者事件傳遞到最底層的View。
可以通過(guò)重寫View的dispatchTouchEvent()方法來(lái)實(shí)現(xiàn)事件的分發(fā)和傳遞。在該方法中,可以根據(jù)需要調(diào)用super.dispatchTouchEvent()方法將事件傳遞給父View或者調(diào)用View的onTouchEvent()方法來(lái)處理事件。
Android中的事件分發(fā)是通過(guò)Activity、Window、View和ViewGroup等對(duì)象之間的協(xié)作來(lái)實(shí)現(xiàn)的。每個(gè)對(duì)象都有機(jī)會(huì)處理事件,通過(guò)合理地重寫相關(guān)方法,可以實(shí)現(xiàn)事件的傳遞和處理。
從上面的文章中我們得知Android事件分發(fā)機(jī)制的傳遞過(guò)程可以分為三個(gè)階段:分發(fā)、攔截和處理。
Android事件分發(fā)機(jī)制的傳遞過(guò)程是從上到下的遞歸過(guò)程,事件會(huì)依次經(jīng)過(guò)父ViewGroup和子View的攔截判斷,最終到達(dá)最底層的View進(jìn)行處理。這個(gè)過(guò)程中,可以通過(guò)重寫相關(guān)方法來(lái)實(shí)現(xiàn)事件的攔截和處理,從而實(shí)現(xiàn)自定義的交互邏輯。
Activity的事件分發(fā)機(jī)制是通過(guò)ViewGroup和View的層級(jí)關(guān)系來(lái)實(shí)現(xiàn)的。當(dāng)用戶觸摸屏幕或者按下按鍵時(shí),系統(tǒng)會(huì)將事件傳遞給當(dāng)前顯示的Activity的根布局ViewGroup,然后由ViewGroup負(fù)責(zé)將事件分發(fā)給各個(gè)子View進(jìn)行處理。
具體的事件分發(fā)流程如下:
通過(guò)這樣的事件分發(fā)機(jī)制,Android系統(tǒng)可以實(shí)現(xiàn)對(duì)用戶的觸摸和按鍵事件進(jìn)行靈活的處理,從而實(shí)現(xiàn)各種交互效果。
Activity源碼:
public boolean dispatchTouchEvent(MotionEvent ev) {
// 開(kāi)始事件都是Dwon,一般第一次都會(huì)進(jìn)入到onUserInteraction
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
onUserInteraction();
}
// 若Window返回true,則會(huì)告訴Activity也返回true。true在所有touch代表著終止,不再繼續(xù)往下一個(gè)事件傳遞了
if (getWindow().superDispatchTouchEvent(ev)) {
return true;
}
return onTouchEvent(ev);
}下面看getWindow().superDispatchTouchEvent(ev); Window是個(gè)抽象類,唯一實(shí)現(xiàn)類為PhoneWindow,定位到PhoneWindow的superDispatchTouchEvent()。
PhoneWindow的源碼:
@Override
public boolean superDispatchTouchEvent(MotionEvent event) {
return mDecor.superDispatchTouchEvent(event);
}mDecor是DecorView類,DecorView是PhoneWindow類的一個(gè)內(nèi)部類。同時(shí)DecorView也是整個(gè)Window中的最頂層View。
DecorView是Android中的一個(gè)類,它是Android系統(tǒng)中的頂級(jí)視圖,用于承載應(yīng)用程序的用戶界面。它是Android窗口系統(tǒng)的一部分,負(fù)責(zé)管理應(yīng)用程序的窗口和布局。
DecorView是一個(gè)特殊的ViewGroup,它包含了應(yīng)用程序的整個(gè)用戶界面,包括狀態(tài)欄、標(biāo)題欄、內(nèi)容區(qū)域等。它是Android應(yīng)用程序的根視圖,所有其他視圖都是DecorView的子視圖。
DecorView的主要作用是提供一個(gè)容器,用于放置應(yīng)用程序的布局和控件。它還負(fù)責(zé)處理用戶輸入事件,如觸摸、滑動(dòng)等,并將其傳遞給相應(yīng)的子視圖進(jìn)行處理。
在Android開(kāi)發(fā)中,我們通常不直接操作DecorView,而是通過(guò)Activity或Fragment來(lái)管理和操作應(yīng)用程序的用戶界面。DecorView在內(nèi)部被Activity或Fragment自動(dòng)創(chuàng)建和管理,開(kāi)發(fā)者只需要關(guān)注布局和控件的設(shè)計(jì)和交互邏輯即可。
DecorView是Android應(yīng)用程序的根視圖,負(fù)責(zé)承載應(yīng)用程序的用戶界面,并提供容器和事件處理功能。
DecorView是一個(gè)特殊的ViewGroup,分發(fā)處理同ViewGroup,下面看ViewGroup的superDispatchTouchEvent()
public boolean superDispatchTouchEvent(MotionEvent event) {
return super.dispatchTouchEvent(event);
}整個(gè)Activity事件分發(fā)過(guò)程如下圖:
圖片
ViewGroup是一種特殊的View,它可以包含其他的View或者ViewGroup。當(dāng)用戶進(jìn)行觸摸操作時(shí),事件會(huì)被傳遞給ViewGroup,并由ViewGroup負(fù)責(zé)將事件分發(fā)給其子View或者子ViewGroup。
ViewGroup的事件分發(fā)機(jī)制主要包括以下幾過(guò)程:
ViewGroup的事件分發(fā)機(jī)制是通過(guò)事件的傳遞、攔截和處理來(lái)實(shí)現(xiàn)的。通過(guò)重寫dispatchTouchEvent()和onInterceptTouchEvent()方法,可以對(duì)事件進(jìn)行自定義的處理。這種機(jī)制可以保證事件在ViewGroup及其子View或者子ViewGroup之間的正確傳遞和處理。
整個(gè)ViewGroup分發(fā)過(guò)程如下圖:
圖片
View事件分發(fā)機(jī)制主要包括三個(gè)關(guān)鍵方法:dispatchTouchEvent、onInterceptTouchEvent和onTouchEvent。
View事件分發(fā)機(jī)制的流程如下:
View#dispatchTouchEvent源碼:
public boolean dispatchTouchEvent(MotionEvent event) {
...
if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED && li.mOnTouchListener.onTouch(this, event)) {
result = true;
}
...
}只有當(dāng)4個(gè)條件都為真才返回true,否則執(zhí)行onTouchEvent(),下面對(duì)這4個(gè)條件逐個(gè)分析:
若在setOnTouchListener返回true,就會(huì)滿足以上4個(gè)條件,并且返回了true,從而使得View.dispatchTouchEvent()直接返回true,事件分發(fā)結(jié)束,不會(huì)執(zhí)行onTouchEvent(event)。
View#onTouchEvent(event)源碼:
public boolean onTouchEvent(MotionEvent event) {
...
// clickable代表該控件是否可點(diǎn)擊,可點(diǎn)擊就進(jìn)入下面條件判斷
if (clickable || (viewFlags & TOOLTIP) == TOOLTIP) {
switch (action) {
// 1. 當(dāng)前的事件 = 抬起View
case MotionEvent.ACTION_UP:
// 經(jīng)過(guò)種種判斷,此處省略
........
if (!focusTaken) {
// 執(zhí)行performClick()
if (mPerformClick == null) {
mPerformClick = new PerformClick();
}
if (!post(mPerformClick)) {
performClickInternal();
}
}
break;
// 2. 當(dāng)前的事件 = 按下View
case MotionEvent.ACTION_DOWN:
// 經(jīng)過(guò)種種判斷,此處省略
break;
// 3. 當(dāng)前的事件 = 結(jié)束事件(非人為原因)
case MotionEvent.ACTION_CANCEL:
// 經(jīng)過(guò)種種判斷,此處省略
break;
// 4. 當(dāng)前的事件 = 滑動(dòng)View
case MotionEvent.ACTION_MOVE:
// 經(jīng)過(guò)種種判斷,此處省略
break;
}
// 若該控件可點(diǎn)擊,就一定返回true
return true;
}
// 若該控件不可點(diǎn)擊,就一定返回false
return false;
...
}整個(gè)View分發(fā)過(guò)程如下圖:
圖片
圖片
dispatchTouchEvent用于分發(fā)觸摸事件。它是ViewGroup類中的一個(gè)方法,用于將觸摸事件傳遞給子View或處理自身的觸摸事件。
觸摸事件的傳遞是通過(guò)觸摸事件分發(fā)機(jī)制來(lái)實(shí)現(xiàn)的。當(dāng)用戶觸摸屏幕時(shí),系統(tǒng)會(huì)將觸摸事件傳遞給頂層的ViewGroup,然后由ViewGroup負(fù)責(zé)將觸摸事件傳遞給子View或處理自身的觸摸事件。
dispatchTouchEvent方法的作用是將觸摸事件分發(fā)給子View或處理自身的觸摸事件。它會(huì)根據(jù)觸摸事件的類型和位置來(lái)確定是將觸摸事件傳遞給子View,還是處理自身的觸摸事件。
在dispatchTouchEvent方法中,會(huì)依次調(diào)用onInterceptTouchEvent方法和onTouchEvent方法來(lái)判斷是否攔截觸摸事件和處理觸摸事件。如果onInterceptTouchEvent方法返回true,則表示攔截觸摸事件,不再向子View傳遞觸摸事件;如果onTouchEvent方法返回true,則表示處理了觸摸事件,不再向子View傳遞觸摸事件。
onTouchEvent用于處理觸摸事件。它是View類的一個(gè)成員方法,可以被重寫以實(shí)現(xiàn)自定義的觸摸事件處理邏輯。
觸摸事件包括按下(ACTION_DOWN)、移動(dòng)(ACTION_MOVE)、抬起(ACTION_UP)等多個(gè)動(dòng)作。當(dāng)用戶觸摸屏幕時(shí),系統(tǒng)會(huì)將觸摸事件傳遞給相應(yīng)的View,并調(diào)用該View的onTouchEvent方法來(lái)處理事件。
在onTouchEvent方法中,可以根據(jù)不同的觸摸動(dòng)作進(jìn)行相應(yīng)的處理,例如根據(jù)觸摸位置進(jìn)行繪制、處理滑動(dòng)事件、處理點(diǎn)擊事件等??梢酝ㄟ^(guò)重寫onTouchEvent方法來(lái)實(shí)現(xiàn)自定義的觸摸交互效果。
重寫onTouchEvent方法來(lái)處理觸摸事件:
@Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
// 處理按下事件
break;
case MotionEvent.ACTION_MOVE:
// 處理移動(dòng)事件
break;
case MotionEvent.ACTION_UP:
// 處理抬起事件
break;
}
return true;
}需要注意的是,onTouchEvent方法的返回值為boolean類型。如果返回true,表示已經(jīng)處理了該觸摸事件,不再向其他View傳遞;如果返回false,則會(huì)將該觸摸事件傳遞給父View或其他相關(guān)的View進(jìn)行處理。
onInterceptTouchEvent用于攔截觸摸事件。它通常用于父容器對(duì)子View的觸摸事件進(jìn)行攔截和處理。
觸摸事件是由屏幕上的觸摸點(diǎn)產(chǎn)生的,包括按下、移動(dòng)和抬起等動(dòng)作。當(dāng)一個(gè)觸摸事件發(fā)生時(shí),系統(tǒng)會(huì)將該事件傳遞給最上層的View,并通過(guò)dispatchTouchEvent方法進(jìn)行分發(fā)。在分發(fā)過(guò)程中,如果父容器的onInterceptTouchEvent方法返回true,則表示父容器要攔截該事件,不再將事件傳遞給子View;如果返回false,則表示父容器不攔截該事件,繼續(xù)將事件傳遞給子View。
onInterceptTouchEvent方法的返回值決定了是否攔截觸摸事件,它有三種可能的返回值:
通過(guò)在onInterceptTouchEvent方法中對(duì)觸摸事件進(jìn)行處理,我們可以實(shí)現(xiàn)一些特定的觸摸事件邏輯,例如滑動(dòng)沖突處理、多指觸摸事件的處理等。
setOnTouchListener是一個(gè)用于設(shè)置觸摸事件監(jiān)聽(tīng)器的方法,用于對(duì)觸摸事件進(jìn)行處理。
使用setOnTouchListener方法,可以為一個(gè)控件(如Button、ImageView等)設(shè)置一個(gè)觸摸事件監(jiān)聽(tīng)器。當(dāng)用戶觸摸該控件時(shí),觸摸事件監(jiān)聽(tīng)器會(huì)被觸發(fā),并執(zhí)行相應(yīng)的操作。
示例代碼:
button.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
// 處理觸摸事件的邏輯代碼
return true; // 返回true表示已經(jīng)處理了觸摸事件,false表示未處理
}
});button是要設(shè)置觸摸事件監(jiān)聽(tīng)器的視圖對(duì)象。setOnTouchListener方法接受一個(gè)View.OnTouchListener對(duì)象作為參數(shù),該對(duì)象實(shí)現(xiàn)了onTouch方法,用于處理觸摸事件。
在onTouch方法中,可以編寫自定義的觸摸事件處理邏輯。根據(jù)MotionEvent對(duì)象的不同動(dòng)作(如按下、移動(dòng)、抬起等),可以執(zhí)行相應(yīng)的操作。最后,需要返回一個(gè)布爾值,表示是否已經(jīng)處理了觸摸事件。
使用setOnTouchListener方法可以實(shí)現(xiàn)各種觸摸事件的處理,例如拖動(dòng)、縮放、滑動(dòng)等。根據(jù)具體需求,可以在onTouch方法中編寫相應(yīng)的代碼邏輯。

我們?cè)谖⑿派?4小時(shí)期待你的聲音
解答本文疑問(wèn)/技術(shù)咨詢/運(yùn)營(yíng)咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流