偽代碼
boolean dispatchTouchEvent(Event event){
boolean result = false;
//第一步重置
if(DOWN){
//DOWN事件中重置。如清空FirstTarget,將禁止攔截標(biāo)志位重置為0
}
//第二步判斷是否要攔截
if(DOWN || firstTarget != null){//firseTarget有值,代表事件曾經(jīng)分發(fā)到了子View
if(禁止攔截標(biāo)志位為0){ //禁止攔截標(biāo)志位可以由子View設(shè)置為1
intercepted = onInterceptTouchEvent();//詢(xún)問(wèn)自己是否要攔截
}else {
intercepted = false;
}
}else {
intercepted = true;
}
//第三步 DOWN事件中的分發(fā)判斷
if(!intercepted){
if(DOWN){
for(int i = childCount-1; i>=0; i--){ //倒著循環(huán),所以訪(fǎng)問(wèn)的是最后添加的View,即最上層顯示的View
View v = childs[i];
if(v在觸摸范圍內(nèi)){
if(v.dispatchTouchEvent(event)){
addTarget(v);//將該v加入firstTarget鏈表中,之所以是個(gè)鏈表因?yàn)橛卸嘀盖闆r,單指不考慮
alreadyDispatchedToNewTouchTarget = true;//用于第四步避免重復(fù)分發(fā)
break;
}
}
}
}
}
//第四步 之后事件的分發(fā)判斷
if(firstTarget == null){//當(dāng)無(wú)子View消耗事件
result = super.dispatchTouchEvent(event);//把自己當(dāng)成一個(gè)View,事件交給自己判斷
}else{
target = firstTarget;
while(target != null){//對(duì)于單指情況,只循環(huán)一次
if(alreadyDispatchedToNewTouchTarget){
result = true;
}else {
v = target.view;
boolean cancelChild = intercepted || v是否需要cancel;
if(cancelChild){
event.setAction(CANCEL);
}
result = v.dispatchTouchEvent(event);
if(cancelChild){
從firstTarget鏈表中移除該v所在的target;
}
target = target.next;
}
}
}
return result;
}
}
···
代碼細(xì)節(jié)
1、mFirstTarget的用處:用于"非DOWN事件"的直接分發(fā)。在DOWN事件中會(huì)通過(guò)循環(huán)來(lái)詢(xún)問(wèn)子View是否消耗事件,如果消耗,mFirstTarget就會(huì)有值,后續(xù)時(shí)間就會(huì)通過(guò)第四步直接對(duì)其進(jìn)行分發(fā)。如果該值為空,說(shuō)明無(wú)子View會(huì)處理事件,則第四步就會(huì)交給自己處理。
2、alreadyDispatchedToNewTouchTarget變量,是為了第三步已經(jīng)分發(fā)了,而在第四步重復(fù)分發(fā)的情況,該變量在非DOWN事件就失去作用了。
結(jié)論
1、先判斷子View是否消耗事件,如果子View不消耗才交由自己消耗。
在DOWN事件中會(huì)通過(guò)循環(huán)來(lái)訪(fǎng)問(wèn)子View,如果消耗,則mFirstTarget有值,的事件通過(guò)mFirstTarget對(duì)目標(biāo)子View直接進(jìn)行分發(fā);如果子View都不消耗,則mFirstTarget無(wú)值,
事件交由自己判斷。
2、決定攔截后,后續(xù)事件交由自己處理
如果DOWN事件中攔截,則mFirstTarget無(wú)值,所以直接交由自己處理
如果非DOWN事件中攔截,則mFirstTarget有值,此時(shí),在第四步中當(dāng)前事件會(huì)清空mFirstTarget中的Target,并對(duì)該Target中的子View發(fā)送CANCEL事件,而后續(xù)事件mFirstTarget等同于無(wú)值處理(即交由自己處理)。并且之后在第二步也不會(huì)再詢(xún)問(wèn)是否要阻止攔截,直接認(rèn)為攔截事件。
3、子View顯示在上層的會(huì)先判斷觸摸事件
因?yàn)榈谌降难h(huán)時(shí)根據(jù)子View的添加順序逆序循環(huán),而最后添加的子View都是顯示在最上層,所以如果最上層子View消耗了事件,被遮擋的子View就無(wú)法收到事件了
4、子View無(wú)法在DOWN事件中阻止其父View攔截事件(如果其父View想要攔截的話(huà))
因?yàn)樽覸iew如果想阻止攔截,是通過(guò)設(shè)置FLAG的方式,然后在第二步會(huì)進(jìn)行判斷。但是第一步DOWN事件會(huì)重置狀態(tài)。