Android View的事件分發(fā)機(jī)制
一.Android View框架提供了3個(gè)對(duì)事件的主要操作概念。
1、事件的分發(fā)機(jī)制,dispatchTouchEvent。主要是parent根據(jù)觸摸事件的產(chǎn)生位置,以及child是否愿意負(fù)責(zé)處理該系列事件等狀態(tài),向其child分發(fā)事件的機(jī)制。
2、事件的攔截機(jī)制,onInterceptTouchEvent。主要是parent根據(jù)它內(nèi)部的狀態(tài)、或者child的狀態(tài),來(lái)把事件攔截下來(lái),阻止其進(jìn)一步傳遞到child的機(jī)制。
3、事件的處理機(jī)制,onTouchEvent。主要是事件序列的接受者(可以是一個(gè)View或者ViewGroup),對(duì)事件作出處理,并且向其parent傳遞處理結(jié)果的機(jī)制。
二.在Java中,傳遞計(jì)算結(jié)果,有很多種途徑,這里采用的是一種適用于同步調(diào)用的方法,返回值的方法。每個(gè)機(jī)制都使用boolean類型作為其返回值,那么每個(gè)機(jī)制的每個(gè)返回值是什么含義呢。
1、事件的分發(fā)機(jī)制,dispatchTouchEvent。
true-事件被以該節(jié)點(diǎn)為根節(jié)點(diǎn)的View樹成功處理,此時(shí)該事件就算是處理完成了,事件不會(huì)再向上返還給View的父節(jié)點(diǎn)(把事件分發(fā)過(guò)來(lái)的那個(gè)節(jié)點(diǎn))。
false-以該節(jié)點(diǎn)為根節(jié)點(diǎn)的View樹種,沒(méi)有一個(gè)View(包括該View)成功處理了此事件,所以事件會(huì)向上返還給View的父節(jié)點(diǎn)(把事件分發(fā)過(guò)來(lái)的那個(gè)節(jié)點(diǎn))。
2、事件的攔截機(jī)制,onInterceptTouchEvent。主要是parent根據(jù)它內(nèi)部的狀態(tài)、或者child的狀態(tài),來(lái)把事件攔截下來(lái),阻止其進(jìn)一步傳遞到child的機(jī)制。
true-當(dāng)前ViewGroup(因?yàn)閂iew中沒(méi)有該方法,而沒(méi)有child的VIew也不需要有攔截機(jī)制)希望該事件不再傳遞給其child,而是希望自己處理。
false-當(dāng)前ViewGroup不準(zhǔn)備攔截該事件,事件正常向下分發(fā)給其child。
3、事件的處理機(jī)制,onTouchEvent。主要是事件序列的接受者(可以是一個(gè)View或者ViewGroup),對(duì)事件作出處理,并且向其parent傳遞處理結(jié)果的機(jī)制。
true-表示該View成功處理了該事件,該處理結(jié)果會(huì)向上通知給其parent。
false-表示該View沒(méi)有成功處理該事件,那么它的parent會(huì)有機(jī)會(huì)來(lái)處理該事件(parent標(biāo)記為事件序列接受者,parent 的 onTouchEvent 在 Down 事件時(shí)返回true)。
三.源代碼分析
View:
1、dispatchTouchEvent:
/** 把事件分發(fā)到目標(biāo)對(duì)象,因?yàn)檫@里是View對(duì)象,默認(rèn)不含有child,所以這里他會(huì)把事件分發(fā)給自己 */
public boolean dispatchTouchEvent(MotionEvent event);
public boolean dispatchTouchEvent(MotionEvent event){
boolean result = false;
//如果有事件監(jiān)聽器,先讓監(jiān)聽器處理事件。
if (mOnTouchListener.onTouch(event)) {
//如果監(jiān)聽器成功處理了該事件,處理結(jié)果設(shè)置為true。
result = true;
}
//如果沒(méi)有監(jiān)聽器,就調(diào)用自身的onTouchEvent方法來(lái)處理事件。
if (!resutlt && onTouchEvent(event)) {
//如果自身的onTouchEvent成功處理事件,處理結(jié)果設(shè)置為true。
result = true;
}
return result;
}
ViewGroup:
1、onInterceptTouchEvent
/** 默認(rèn)實(shí)現(xiàn)是返回false,也就是默認(rèn)不攔截任何事件 */
public boolean onInterceptTouchEvent(MotionEvent ev);
2、dispatchTouchEvent
/** 根據(jù)內(nèi)部攔截狀態(tài),向其child或者自己分發(fā)事件 */
public boolean dispatchTouchEvent(MotionEvent ev);
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ACTION_DOWN事件 || 沒(méi)有事件處理對(duì)象) {
if (允許攔截事件,該標(biāo)志位由child調(diào)用requestDisallowInterceptTouchEvent<span style="font-family:微軟雅黑;font-size:14px;">設(shè)置</span>) {
//查詢攔截機(jī)制的結(jié)果,根據(jù)該結(jié)果來(lái)判斷是否需要攔截
intercepted = onInterceptTouchEvent(ev);
} else {
//不允許攔截,那么不攔截
intercepted = false;
}
} else {
//不是DOWN,并且有處理對(duì)象,允許攔截,中斷事件傳遞
intercepted = true;
}
if (不取消 && 不攔截) {
if (ACTION_DOWN) { //找尋接收事件序列的對(duì)象,其他事件不需要再計(jì)算事件產(chǎn)生對(duì)象,試想一下滑動(dòng)一個(gè)ListView,當(dāng)手指滑動(dòng)出ListView的范圍時(shí),依然還是ListView響應(yīng)后續(xù)事件。
for (遍歷所有childView) {
if (觸摸點(diǎn)不在childView內(nèi)部) {
continue;
}
if (childView.dispatchTouchEvent(event)) {
保存處理該事件的View,后續(xù)事件直接傳遞到該View,不要重新計(jì)算;
}
}
}
if (還沒(méi)有事件處理對(duì)象) {
//當(dāng)前View樹中沒(méi)找到合適的child處理對(duì)象,把事件給自己處理,View.dispatchTouchEvent()就是把事件分發(fā)給自己
super.dispatchTouchEvent(event);
} else {
//傳遞給child
childView.dispatchTouchEvent(event);
}
} else if (攔截) {
//攔截事件,把事件給自己處理,View.dispatchTouchEvent()就是把事件分發(fā)給自己
super.dispatchTouchEvent(event);
}
return 處理結(jié)果;
}
3、requestDisallowInterceptTouchEvent
/** 干澀parent的事件分發(fā)機(jī)制,通知parent,是否攔截后續(xù)事件,如果設(shè)置為true,parent就不會(huì)攔截該事件,不管什么狀態(tài)。設(shè)置為false,parent走正常的攔截流程 */
public void requestDisallowInterceptTouchEvent(boolean disallowIntercept);
public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
if (已經(jīng)是當(dāng)前要設(shè)置的狀態(tài)) {
// 已經(jīng)處于這個(gè)狀態(tài), 假設(shè)我們的parent也是這個(gè)狀態(tài)
return;
}
設(shè)置該狀態(tài);
// 傳遞給parent
if (有父容器) {
設(shè)置父容器的攔截狀態(tài);
}
}
以上就是本文的全部?jī)?nèi)容,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來(lái)一定的幫助,同時(shí)也希望多多支持腳本之家!
相關(guān)文章
Flutter應(yīng)用程序?qū)崿F(xiàn)隱私屏幕示例解析
這篇文章主要為大家介紹了Flutter應(yīng)用程序?qū)崿F(xiàn)隱私屏幕示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-09-09
Android應(yīng)用中使用DOM方式解析XML格式數(shù)據(jù)的基本方法
這篇文章主要介紹了Android應(yīng)用中使用DOM方式解析XML格式數(shù)據(jù)的基本方法,值得注意的是DOM方式解析的效率并不高,在數(shù)據(jù)量大的時(shí)候并不推薦使用,需要的朋友可以參考下2016-04-04
android 仿微信demo——微信主界面實(shí)現(xiàn)
本系列文章主要介紹了微信小程序-閱讀小程序?qū)嵗╠emo),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧,希望能給你們提供幫助2021-06-06
Android滑動(dòng)優(yōu)化高仿QQ6.0側(cè)滑菜單(滑動(dòng)優(yōu)化)
之前的實(shí)現(xiàn)只是簡(jiǎn)單的可以顯示和隱藏左側(cè)的菜單,但是特別生硬,而且沒(méi)有任何平滑的趨勢(shì),那么今天就來(lái)優(yōu)化一下吧,加上平滑效果,而且可以根據(jù)手勢(shì)滑動(dòng)的方向來(lái)判斷是否是顯示和隱藏2016-02-02
Android布局耗時(shí)監(jiān)測(cè)的三種實(shí)現(xiàn)方式
在Android應(yīng)用開發(fā)中,性能優(yōu)化是一個(gè)至關(guān)重要的方面,為了更好地監(jiān)測(cè)布局渲染的耗時(shí),我們需要一種可靠的實(shí)現(xiàn)方案,本文將介紹三種針對(duì)Android布局耗時(shí)監(jiān)測(cè)的實(shí)現(xiàn)方案,幫助開發(fā)者及時(shí)發(fā)現(xiàn)并解決布局性能問(wèn)題,需要的朋友可以參考下2024-03-03
Android權(quán)限操作之uses-permission詳解
這篇文章主要介紹了Android權(quán)限操作之uses-permission,較為詳細(xì)的分析了uses-permission常見權(quán)限操作類型與功能,需要的朋友可以參考下2016-10-10
Android入門之使用RecyclerView完美實(shí)現(xiàn)瀑布流界面詳解
網(wǎng)上充滿著不完善的基于RecyclerView的瀑布流實(shí)現(xiàn),要么根本是錯(cuò)的、要么就是只知其一不知其二。本文就來(lái)用RecyclerView完美實(shí)現(xiàn)瀑布流界面,希望大家有所幫助2023-02-02

