你確定你對(duì)Android事件分發(fā)機(jī)制了然于胸了嗎?如果能麻溜的回答出下面幾個(gè)問題窝剖,還請(qǐng)大佬繞道沃饶,如果不能,請(qǐng)聽我細(xì)細(xì)講解:
1.View事件分發(fā)機(jī)制的傳遞過程是石抡?onTouch檐嚣,onTouchEvent,onClick的執(zhí)行順序汁雷?
2.DOWN事件分發(fā)機(jī)制的傳遞過程净嘀?遇到過滑動(dòng)沖突嗎报咳?怎么解決的?
3.MOVE事件分發(fā)機(jī)制的傳遞過程挖藏?
4.事件分發(fā)機(jī)制流程及優(yōu)缺點(diǎn)?
1. View事件分發(fā)機(jī)制的傳遞過程
1.1 View#dispatchTouchEvent:onTouch
public boolean dispatchTouchEvent(MotionEvent event) {
// 事件消費(fèi)默認(rèn)返回false
boolean result = false;
// 觸摸事件安全過濾
if (onFilterTouchEventForSecurity(event)) {
// 判斷有沒有注冊(cè)onTouchListener暑刃,onTouch事件是否被消費(fèi)
// 如果事件被onTouch消費(fèi)就不會(huì)繼續(xù)往下執(zhí)行;
// 如果沒有被消費(fèi)膜眠,繼續(xù)執(zhí)行onTouchEvent方法岩臣。
ListenerInfo li = mListenerInfo;
if (li != null && li.mOnTouchListener != null
&& (mViewFlags & ENABLED_MASK) == ENABLED
&& li.mOnTouchListener.onTouch(this, event)) {
result = true;
}
// 如果onTouchEvent事件被消費(fèi),則事件被消費(fèi)宵膨;
// 如果onTouchEvent事件沒有被消費(fèi)架谎,那么事件依然會(huì)繼續(xù)往下傳遞。
if (!result && onTouchEvent(event)) {
result = true;
}
}
return result;
}
1.2 View#onTouchEvent:onTouchEvent
public boolean onTouchEvent(MotionEvent event) {
// 判斷是否注冊(cè)點(diǎn)擊事件
final boolean clickable = ((viewFlags & CLICKABLE) == CLICKABLE
|| (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)
|| (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE;
// 有點(diǎn)擊事件判斷action
if (clickable || (viewFlags & TOOLTIP) == TOOLTIP) {
switch (action) {
case MotionEvent.ACTION_UP:
// ACTION_UP事件觸發(fā)時(shí)辟躏,執(zhí)行performClick方法谷扣。
performClick();
break;
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_CANCEL:
break;
case MotionEvent.ACTION_MOVE:
break;
}
return true;
}
return false;
}
1.3 View#performClick:onClick
public boolean performClick() {
final boolean result;
final ListenerInfo li = mListenerInfo;
// 如果設(shè)置了onClickListener,就會(huì)執(zhí)行onClick方法捎琐,事件就會(huì)被消費(fèi)会涎。
if (li != null && li.mOnClickListener != null) {
playSoundEffect(SoundEffectConstants.CLICK);
li.mOnClickListener.onClick(this);
result = true;
} else {
result = false;
}
return result;
}
小貼士:
View沒有onInterceptTouchEvent方法,當(dāng)有點(diǎn)擊事件傳遞給它時(shí)瑞凑,就會(huì)執(zhí)行onTouchEvent方法末秃。
onTouchEvent方法:默認(rèn)消耗事件,但是如果View不可點(diǎn)擊就不會(huì)消耗事件籽御。
onClick事件會(huì)發(fā)生的前提:當(dāng)前View可點(diǎn)擊练慕,并且收到了down和up事件。
方法執(zhí)行順序:onTouch-onTouchEvent-onClick
思考:
一個(gè)需求:onTouch返回true要執(zhí)行onClick技掏。
解決辦法:在onTouch方法里ACTION_DOWN里加v.performClick();
場景:上層popupwindow擋住了下層view的點(diǎn)擊事件
上層popupwindow設(shè)置isTouchable=false
2.DOWN事件分發(fā)機(jī)制的傳遞過程:
2.1 Activity#dispatchTouchEvent:
當(dāng)我們點(diǎn)擊屏幕時(shí)铃将,觸發(fā)MotionEvent.ACTION_DOWN事件,此時(shí)屏幕處于Activity界面哑梳,Activity#dispatchTouchEvent方法進(jìn)行事件分發(fā):
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
// 執(zhí)行和用戶交互的操作
// 例如聰明的管理狀態(tài)欄通知麸塞,幫助activity在正確的時(shí)間取消通知
onUserInteraction();
}
// 將事件傳遞給Window,Window#superDispatchTouchEvent進(jìn)行事件分發(fā)
if (getWindow().superDispatchTouchEvent(ev)) {
// Window消費(fèi)了該事件涧衙,直接return退出該方法
return true;
}
4
// Window沒有消費(fèi)該事件哪工,繼續(xù)由Activity#onTouchEvent方法來處理
return onTouchEvent(ev);
}
小貼士:
return的用法:
結(jié)束該方法,繼續(xù)執(zhí)行方法后面的語句弧哎。
2.2 Window#superDispatchTouchEvent:
public abstract boolean superDispatchTouchEvent(MotionEvent event);
Window類:抽象類雁比,superDispatchTouchEvent是抽象方法。
看Window類的介紹撤嫩,這個(gè)抽象類的唯一存在實(shí)現(xiàn)是PhoneWindow偎捎。
雙擊shift,搜索PhoneWindow類。
PhoneWindow#superDispatchTouchEvent:
@Override
public boolean superDispatchTouchEvent(MotionEvent event) {
// PhoneWindow將事件傳遞給了DecorView
return mDecor.superDispatchTouchEvent(event);
}
2.3 DecorView#superDispatchTouchEvent:
public boolean superDispatchTouchEvent(MotionEvent event) {
// DecorView將事件傳遞給了ViewGroup
return super.dispatchTouchEvent(event);
}
2.4 ViewGroup#dispatchTouchEvent:
@Override
// 事件分發(fā):dispatchTouchEvent
public boolean dispatchTouchEvent(MotionEvent ev) {
boolean handled = false;
if (onFilterTouchEventForSecurity(ev)) {
// 注釋1
// 初始化的原因:一個(gè)完整的事件序列是以DOWN開始茴她,以UP結(jié)束的寻拂。
// 如果是DOWN事件,說明這是一個(gè)新的事件序列丈牢,所以需要初始化之前的狀態(tài)祭钉。
if (actionMasked == MotionEvent.ACTION_DOWN) {
// 清除觸摸目標(biāo)
cancelAndClearTouchTargets(ev);
// 重置觸摸狀態(tài)
// mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT代碼意思是:將FLAG_DISALLOW_INTERCEPT標(biāo)志位設(shè)置為false。
resetTouchState();
}
// 注釋2
final boolean intercepted;
if (actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null) {
// 因?yàn)槌跏蓟号妫栽撝禐閒alse
final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
if (!disallowIntercept) {
// 事件攔截:onInterceptTouchEvent
// onInterceptTouchEvent返回true慌核,intercepted為true;
// onInterceptTouchEvent返回false申尼,intercepted為false垮卓。
intercepted = onInterceptTouchEvent(ev);
} else {
intercepted = false;
}
} else {
intercepted = true;
}
// 注釋3
final boolean canceled = resetCancelNextUpFlag(this) || actionMasked == MotionEvent.ACTION_CANCEL;
// 注釋4
TouchTarget newTouchTarget = null;
if (!canceled && !intercepted) {
if (actionMasked == MotionEvent.ACTION_DOWN
|| (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)
|| actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
final int childrenCount = mChildrenCount;
if (newTouchTarget == null && childrenCount != 0) {
final ArrayList<View> preorderedList = buildTouchDispatchChildList();
for (int i = childrenCount - 1; i >= 0; i--) {
// 注釋5
final int childIndex = getAndVerifyPreorderedIndex(
childrenCount, i, customOrder);
final View child = getAndVerifyPreorderedView(
preorderedList, children, childIndex);
// 注釋6
if (!canViewReceivePointerEvents(child)
|| !isTransformedTouchPointInView(x, y, child, null)) {
ev.setTargetAccessibilityFocus(false);
continue;
}
// 注釋7
newTouchTarget = getTouchTarget(child);
if (newTouchTarget != null) {
newTouchTarget.pointerIdBits |= idBitsToAssign;
break;
}
// 注釋8
resetCancelNextUpFlag(child);
if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
if (preorderedList != null) {
for (int j = 0; j < childrenCount; j++) {
if (children[childIndex] == mChildren[j]) {
mLastTouchDownIndex = j;
break;
}
}
} else {
mLastTouchDownIndex = childIndex;
}
newTouchTarget = addTouchTarget(child, idBitsToAssign);
alreadyDispatchedToNewTouchTarget = true;
break;
}
ev.setTargetAccessibilityFocus(false);
}
if (preorderedList != null) preorderedList.clear();
}
if (newTouchTarget == null && mFirstTouchTarget != null) {
newTouchTarget = mFirstTouchTarget;
while (newTouchTarget.next != null) {
newTouchTarget = newTouchTarget.next;
}
newTouchTarget.pointerIdBits |= idBitsToAssign;
}
}
}
// 注釋9:
if (mFirstTouchTarget == null) {
handled = dispatchTransformedTouchEvent(ev, canceled, null,
TouchTarget.ALL_POINTER_IDS);
} else {
TouchTarget predecessor = null;
TouchTarget target = mFirstTouchTarget;
while (target != null) {
final TouchTarget next = target.next;
if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {
handled = true;
} else {
final boolean cancelChild = resetCancelNextUpFlag(target.child)
|| intercepted;
if (dispatchTransformedTouchEvent(ev, cancelChild,
target.child, target.pointerIdBits)) {
handled = true;
}
if (cancelChild) {
if (predecessor == null) {
mFirstTouchTarget = next;
} else {
predecessor.next = next;
}
target.recycle();
target = next;
continue;
}
}
predecessor = target;
target = next;
}
}
// 注釋10
if (canceled
|| actionMasked == MotionEvent.ACTION_UP
|| actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
resetTouchState();
} else if (split && actionMasked == MotionEvent.ACTION_POINTER_UP) {
final int actionIndex = ev.getActionIndex();
final int idBitsToRemove = 1 << ev.getPointerId(actionIndex);
removePointersFromTouchTargets(idBitsToRemove);
}
}
return handled;
}
Down事件:
注釋1:見代碼。
注釋2:
當(dāng)onInterceptTouchEvent返回true师幕,intercepted為true粟按,執(zhí)行注釋9。
mFirstTouchTarget為空霹粥,沒有進(jìn)行任何賦值钾怔,執(zhí)行dispatchTransformedTouchEvent方法。
dispatchTransformedTouchEvent:
canceled值:看注釋3#resetCancelNextUpFlag默認(rèn)為false蒙挑,且沒有執(zhí)行ACTION_CANCEL事件,所以值為false愚臀。
private static boolean resetCancelNextUpFlag(@NonNull View view) {
// 如果if條件boolean類型為true忆蚀,條件置為false,該方法返回true
if ((view.mPrivateFlags & PFLAG_CANCEL_NEXT_UP_EVENT) != 0) {
view.mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT;
return true;
}
// 該方法默認(rèn)返回false
return false;
}
dispatchTransformedTouchEvent:cancel為false姑裂,child為null馋袜,執(zhí)行注釋2:
private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,
View child, int desiredPointerIdBits) {
final boolean handled;
final int oldAction = event.getAction();
// 注釋1
if (cancel || oldAction == MotionEvent.ACTION_CANCEL) {
event.setAction(MotionEvent.ACTION_CANCEL);
if (child == null) {
handled = super.dispatchTouchEvent(event);
} else {
handled = child.dispatchTouchEvent(event);
}
event.setAction(oldAction);
return handled;
}
// 注釋2
if (child == null) {
// 執(zhí)行View#dispatchTouchEvent
// super關(guān)鍵字:用來調(diào)用超類里的方法,ViewGroup繼承View舶斧。
// 事件交給父容器來處理欣鳖。
handled = super.dispatchTouchEvent(transformedEvent);
} else {
handled = child.dispatchTouchEvent(transformedEvent);
}
return handled;
}
當(dāng)onInterceptTouchEvent返回false,intercepted為false茴厉,假設(shè)canceled依然為false泽台,執(zhí)行注釋4。
執(zhí)行DOWN事件矾缓,newTouchTarget為空怀酷,mChildrenCount為ViewGroup中所有子View的數(shù)量不為0,執(zhí)行buildTouchDispatchChildList方法:
public ArrayList<View> buildTouchDispatchChildList() {
// 對(duì)事件進(jìn)行排序
return buildOrderedChildList();
}
buildOrderedChildList:將子視圖從ViewGroup到View(比如Button)從前往后依次有序添加到list集合中嗜闻,Z軸不斷增大蜕依。
ArrayList<View> buildOrderedChildList() {
if (mPreSortedChildren == null) {
mPreSortedChildren = new ArrayList<>(childrenCount);
} else {
mPreSortedChildren.clear();
mPreSortedChildren.ensureCapacity(childrenCount);
}
for (int i = 0; i < childrenCount; i++) {
final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
final View nextChild = mChildren[childIndex];
final float currentZ = nextChild.getZ();
int insertIndex = i;
while (insertIndex > 0 && mPreSortedChildren.get(insertIndex - 1).getZ() > currentZ) {
insertIndex--;
}
mPreSortedChildren.add(insertIndex, nextChild);
}
return mPreSortedChildren;
}
回到注釋4:執(zhí)行for循環(huán)。
注釋5:從后往前第一個(gè)得到的View為Button。
注釋6:判斷View是否能收到點(diǎn)擊事件和點(diǎn)是否在它的坐標(biāo)里样眠。如果不能收到點(diǎn)擊事件或者不在坐標(biāo)里友瘤,繼續(xù)。
注釋7:getTouchTarget為空值檐束,執(zhí)行注釋8辫秧。
注釋8:
執(zhí)行dispatchTransformedTouchEvent方法,child不為空厢塘,執(zhí)行child#dispatchTouchEvent方法即View#dispatchTouchEvent方法茶没。即Button在處理事件。如果Button處理了事件晚碾,執(zhí)行注釋8的if里的內(nèi)容抓半。先拿到所有點(diǎn)擊事件的索引,然后用addTouchTarget方法將child賦值給mFirstTouchTarget格嘁,newTouchTarget為mFirstTouchTarget笛求,alreadyDispatchedToNewTouchTarget賦值為true。最后執(zhí)行break退出整個(gè)for循環(huán)糕簿。
注意:
如果注釋8的View沒有把事件消費(fèi)掉探入,那么剩余的Activity,Window懂诗,ViewGroup就會(huì)一直調(diào)用dispatchTransformTouchEvent處理事件直到把事件消費(fèi)為止蜂嗽。只要子View處理了事件,父View就再也不會(huì)接收到事件殃恒。
注釋9:
mFirstTouchTarget不為空植旧,target.next為空,handled為true离唐。
小貼士:
二進(jìn)制和按位操作符:& | ~
break:退出for循環(huán)病附。
2.5 ViewGroup#requestDisallowInterceptedTouchEvent:
定義:子View通過調(diào)用父View的requestDisallowInterceptTouchEvent方法來要求父View不攔截事件。
即:子View調(diào)用getParent().requestDisallowInterceptTouchEvent();
requestDisallowInterceptTouchEvent傳的值true亥鬓,disallowIntercept為true完沪。
當(dāng)為DOWN事件時(shí),ViewGroup#dispatchTouchEvent中注釋2處intercepted為false嵌戈,會(huì)執(zhí)行注釋4覆积,向子View傳遞。
@Override
public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
if (disallowIntercept == ((mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0)) {
return;
}
if (disallowIntercept) {
mGroupFlags |= FLAG_DISALLOW_INTERCEPT;
} else {
mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
}
if (mParent != null) {
mParent.requestDisallowInterceptTouchEvent(disallowIntercept);
}
}
標(biāo)志位FLAG_DISALLOW_INTERCEPT的作用:
要求父View不攔截事件熟呛,向子View傳遞技健。
DOWN事件除外。因?yàn)槿绻茿CTION_DOWN事件惰拱,每次都會(huì)在注釋1處重置手勢(shì)狀態(tài)雌贱。
小結(jié):
DOWN事件的流程:
事件分發(fā)從父容器向子容器分發(fā)啊送。
事件分發(fā):dispatchTouchEvent
事件攔截:onInterceptTouchEvent。
為true不執(zhí)行注釋4欣孤,事件由父容器處理馋没;
為false執(zhí)行注釋4,向子View傳遞降传,發(fā)生到ViewGroup時(shí)篷朵,先問Button處不處理該事件,不處理就交給ViewGroup婆排,再根據(jù)for循環(huán)一層一層向上處理声旺。
ViewGroup想要攔截事件,可以重寫onInterceptTouchEvent方法返回true段只。
事件排序:buildTouchDispatchChildList腮猖,是為了從下往上排序處理。
事件處理:dispatchTransformedTouchEvent
事件消費(fèi):onTouchEvent
流程圖:
[圖片上傳失敗...(image-39be25-1692928698844)])
問題:
父View#onInterceptedTouchEvent設(shè)置為true赞枕,
DOWN事件requestDisallowInterceptedTouchEvent為true不起作用澈缺,還是會(huì)被父View攔截。
原因:
DOWN事件會(huì)在注釋1處進(jìn)行初始化炕婶,清除狀態(tài)姐赡,導(dǎo)致disallowIntercept為false執(zhí)行onInterceptTouchEvent方法為true被父View攔截。
解決:(重點(diǎn))
父View#onInterceptedTouchEvent:
當(dāng)點(diǎn)擊事件為ACTION_DOWN時(shí)柠掂,return false项滑,向子View傳遞。
如果onInterceptedTouchEvent是重寫的方法涯贞,還要寫方法super.onInterceptTouchEvent枪狂。
3.MOVE事件分發(fā)機(jī)制的傳遞過程:
執(zhí)行完DOWN事件就開始執(zhí)行MOVE事件。
3.1 ViewGroup#dispatchTouchEvent:
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
boolean handled = false;
if (onFilterTouchEventForSecurity(ev)) {
// 注釋1:不執(zhí)行
if (actionMasked == MotionEvent.ACTION_DOWN) {
cancelAndClearTouchTargets(ev);
resetTouchState();
}
// 注釋2:if 語句第二個(gè)條件mFirstTouchTarget不為空滿足
final boolean intercepted;
if (actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null) {
final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
if (!disallowIntercept) {
// 事件攔截:onInterceptTouchEvent
intercepted = onInterceptTouchEvent(ev);
} else {
intercepted = false;
}
} else {
intercepted = true;
}
// 注釋3
final boolean canceled = resetCancelNextUpFlag(this) || actionMasked == MotionEvent.ACTION_CANCEL;
// 注釋4
TouchTarget newTouchTarget = null;
// 第一個(gè) if 語句
if (!canceled && !intercepted) {
// 第二個(gè) if 語句
if (actionMasked == MotionEvent.ACTION_DOWN
|| (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)
|| actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
final int childrenCount = mChildrenCount;
if (newTouchTarget == null && childrenCount != 0) {
final ArrayList<View> preorderedList = buildTouchDispatchChildList();
for (int i = childrenCount - 1; i >= 0; i--) {
// 注釋5
final int childIndex = getAndVerifyPreorderedIndex(
childrenCount, i, customOrder);
final View child = getAndVerifyPreorderedView(
preorderedList, children, childIndex);
// 注釋6
if (!canViewReceivePointerEvents(child)
|| !isTransformedTouchPointInView(x, y, child, null)) {
ev.setTargetAccessibilityFocus(false);
continue;
}
// 注釋7
newTouchTarget = getTouchTarget(child);
if (newTouchTarget != null) {
newTouchTarget.pointerIdBits |= idBitsToAssign;
break;
}
// 注釋8
resetCancelNextUpFlag(child);
if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
if (preorderedList != null) {
for (int j = 0; j < childrenCount; j++) {
if (children[childIndex] == mChildren[j]) {
mLastTouchDownIndex = j;
break;
}
}
} else {
mLastTouchDownIndex = childIndex;
}
newTouchTarget = addTouchTarget(child, idBitsToAssign);
alreadyDispatchedToNewTouchTarget = true;
break;
}
ev.setTargetAccessibilityFocus(false);
}
if (preorderedList != null)
preorderedList.clear();
}
if (newTouchTarget == null && mFirstTouchTarget != null) {
newTouchTarget = mFirstTouchTarget;
while (newTouchTarget.next != null) {
newTouchTarget = newTouchTarget.next;
}
newTouchTarget.pointerIdBits |= idBitsToAssign;
}
}
}
// 注釋9:
// 第一個(gè) if-else 語句
if (mFirstTouchTarget == null) {
handled = dispatchTransformedTouchEvent(ev, canceled, null,
TouchTarget.ALL_POINTER_IDS);
} else {
TouchTarget predecessor = null;
TouchTarget target = mFirstTouchTarget;
while (target != null) {
final TouchTarget next = target.next;
// 第二個(gè) if-else 語句
if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {
handled = true;
} else {
final boolean cancelChild = resetCancelNextUpFlag(target.child)
|| intercepted;
// 第三個(gè) if 語句
if (dispatchTransformedTouchEvent(ev, cancelChild,
target.child, target.pointerIdBits)) {
handled = true;
}
// 第四個(gè) if 語句
if (cancelChild) {
if (predecessor == null) {
mFirstTouchTarget = next;
} else {
predecessor.next = next;
}
target.recycle();
target = next;
continue;
}
}
predecessor = target;
target = next;
}
}
// 注釋10
if (canceled
|| actionMasked == MotionEvent.ACTION_UP
|| actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
resetTouchState();
} else if (split && actionMasked == MotionEvent.ACTION_POINTER_UP) {
final int actionIndex = ev.getActionIndex();
final int idBitsToRemove = 1 << ev.getPointerId(actionIndex);
removePointersFromTouchTargets(idBitsToRemove);
}
}
return handled;
}
默認(rèn):
注釋2:onInterceptTouchEvent默認(rèn)返回false肩狂,執(zhí)行注釋4。
注釋4:第一個(gè) if 語句滿足姥饰,第二個(gè) if 語句 不滿足傻谁,執(zhí)行注釋9。
注釋9:
第一個(gè) if-else 語句列粪,mFirstTouchTarget是全局屬性审磁,在DOWN事件后不為空,執(zhí)行else岂座。
第二個(gè) if-else 語句态蒂,newTouchTarget是局部屬性,沒有執(zhí)行注釋4里的語句费什,所以為空钾恢,執(zhí)行else。
第三個(gè) if 語句,執(zhí)行dispatchTransformedTouchEvent方法瘩蚪,cancel為false泉懦,child不為空,執(zhí)行方法里注釋2的else語句即child.dispatchTouchEvent方法疹瘦。
第一次MOVE崩哩,父View攔截子View:
注釋2:假設(shè)onInterceptTouchEvent返回true,不執(zhí)行注釋4言沐,執(zhí)行注釋9邓嘹。
注釋9:
第一個(gè) if-else 語句,同上险胰。
第二個(gè) if-else 語句汹押,同上。
第三個(gè) if 語句:
執(zhí)行dispatchTransformedTouchEvent方法鸯乃,cancel為true鲸阻,child不為空,執(zhí)行方法里的注釋1缨睡。
MotionEvent事件設(shè)置為了ACTION_CANCEL鸟悴,調(diào)用child.dispatchTouchEvent方法,但是最后事件還是oldAction即MOVE事件奖年。
重點(diǎn):此處child取消了事件细诸。
第四個(gè) if 語句:將mFirstTouchTarget置為了空。
第二次MOVE:
MOVE事件會(huì)多次觸發(fā)陋守,再從執(zhí)行MOVE事件:
注釋2:執(zhí)行 else 語句 intercepted = true 部分震贵。
注釋4:不執(zhí)行
注釋9:執(zhí)行第一個(gè) if-else 語句的 if 語句,即 dispatchTransformedTouchEvent方法水评,cancel為false猩系,child為空,執(zhí)行方法里注釋2的else語句super.dispatchTouchEvent即父View它自己的dispatchTouchEvent中燥。
流程圖:
[圖片上傳失敗...(image-f7701e-1692928698844)])
MotionEvent中的四個(gè)事件:
ACTION_DOWN:手指初次接觸到屏幕時(shí)觸發(fā)
ACTION_MOVE:手指在屏幕上滑動(dòng)時(shí)觸發(fā)寇甸,會(huì)多次觸發(fā)
ACTION_UP:手指離開屏幕時(shí)觸發(fā)
ACTION_CANCEL:事件被上層攔截時(shí)觸發(fā)
4.事件分發(fā)機(jī)制流程及優(yōu)缺點(diǎn):
事件分發(fā)機(jī)制其實(shí)是一個(gè)責(zé)任鏈模式,上級(jí)交給下級(jí),下級(jí)完成不了再交給上級(jí)。但是這樣做的缺點(diǎn)是層級(jí)太多同云,不夠扁平化。
[圖片上傳失敗...(image-5d1707-1692928698844)])