日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > Android >内容正文

Android

android viewgroup点击变色,Android ViewGroup事件分发

發(fā)布時(shí)間:2023/12/2 Android 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 android viewgroup点击变色,Android ViewGroup事件分发 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

上篇文章已經(jīng)分析了Android的Touch事件分發(fā)。如果沒看的建議先看一下。Android View的Touch事件分發(fā)。

接下來我們開始寫幾種場(chǎng)景,得出一個(gè)初步的執(zhí)行順序,然后我們按照這個(gè)順序開始分析。

首先我們自定義一個(gè)ViewGroup和一個(gè)View,然后重寫相關(guān)事件進(jìn)行打印:

場(chǎng)景一:正常返回super,TouchView設(shè)置click和onTouchListener事件(onTouch返回false)

TouchViewGroup.png

TouchView.png

布局.png

TouchView設(shè)置事件.png

這時(shí)候我們點(diǎn)擊一下TouchView,觸發(fā)事件:

點(diǎn)擊一下.png

可以看到觸發(fā)的DOWN MOVE UP事件順序都為:

ViewGroup.dispatchTouchEvent -> ViewGroup.onInterceptTouchEvent -> View.dispatchTouchEvent -> View.onTouch -> View.onTouchEven

只是在UP事件的時(shí)候最后多了一個(gè)click事件。

場(chǎng)景二:在場(chǎng)景一的基礎(chǔ)上取消TouchView的onClick事件

TouchView取消click事件.png

這時(shí)候發(fā)現(xiàn)除了,執(zhí)行的順序變?yōu)榱?#xff1a;

ViewGroup.dispatchTouchEvent -> ViewGroup.onInterceptTouchEvent -> View.dispatchTouchEvent -> View.onTouch -> View.onTouchEven->ViewGroup.onTouchEven

并且只有DOWN事件,其他事件就沒有了。

場(chǎng)景三:在場(chǎng)景二的基礎(chǔ)上TouchViewGroup的onInterceptTouchEvent里面返回true

這個(gè)時(shí)候就只有DOWN事件,并且順序?yàn)?

ViewGroup.dispatchTouchEvent -> ViewGroup.onInterceptTouchEvent -> ViewGroup.onTouchEvent

接下來我們通過源碼來分析:

首先從ViewGroup的dispatchTouchEvent入手

@Override

public boolean dispatchTouchEvent(MotionEvent ev) {

//...

boolean handled = false;

//...

//1.取消之前的手勢(shì)

// Handle an initial down.

if (actionMasked == MotionEvent.ACTION_DOWN) {

// Throw away all previous state when starting a new touch gesture.

// The framework may have dropped the up or cancel event for the previous gesture

// due to an app switch, ANR, or some other state change.

cancelAndClearTouchTargets(ev);

resetTouchState();

}

//2.判斷是否攔截

// Check for interception.

final boolean intercepted;

if (actionMasked == MotionEvent.ACTION_DOWN

|| mFirstTouchTarget != null) { //DOWN

//父類是否攔截 getParent().requestDisallowInterceptTouchEvent();來改變值

final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;

if (!disallowIntercept) {

intercepted = onInterceptTouchEvent(ev);

ev.setAction(action); // restore action in case it was changed

} else {

intercepted = false;

}

} else {

// There are no touch targets and this action is not an initial down

// so this view group continues to intercept touches.

intercepted = true;

}

//....

//3.0 如果是不取消不攔截為down,并且dispatchTransformedTouchEvent返回為true的時(shí)候會(huì)為 mFirstTouchTarget賦值

// Check for cancelation.

final boolean canceled = resetCancelNextUpFlag(this)

|| actionMasked == MotionEvent.ACTION_CANCEL;

// Update list of touch targets for pointer down, if needed.

final boolean split = (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) != 0;

TouchTarget newTouchTarget = null;

boolean alreadyDispatchedToNewTouchTarget = false;

//3.1 如果不取消并且不攔截的情況下,

if (!canceled && !intercepted) {

if (actionMasked == MotionEvent.ACTION_DOWN

|| (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)

|| actionMasked == MotionEvent.ACTION_HOVER_MOVE) {// 3.2 DOWN的時(shí)候

//...

if (newTouchTarget == null && childrenCount != 0) {

//...

final View[] children = mChildren;

for (int i = childrenCount - 1; i >= 0; i--) {//3.3 反序for循環(huán),為了先拿到上層的view

//...

//3.4 拿到child

final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);

//...

//3.5 根據(jù)child給newTouchTarget賦值 DOWN的時(shí)候因?yàn)?mFirstTouchTarget==null 所以進(jìn)不去 返回的是null

newTouchTarget = getTouchTarget(child);

}

//...

//3.6. 執(zhí)行操作 是執(zhí)行自己的dispatchTouchEvent還是child的dispatchTouchEvent

if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {

//...

//3.7 子View如果返回true添加一個(gè)newTouchTarget 并且為mFirstTouchTarget賦值

newTouchTarget = addTouchTarget(child, idBitsToAssign);

//....

}

}

}

}

//...

// Dispatch to touch targets.

if (mFirstTouchTarget == null) {//執(zhí)行自身的dispatchTouchEvent

// No touch targets so treat this as an ordinary view.

handled = dispatchTransformedTouchEvent(ev, canceled, null,

TouchTarget.ALL_POINTER_IDS);

} else {// mFirstTouchTarget已經(jīng)賦值

// Dispatch to touch targets, excluding the new touch target if we already

// dispatched to it. Cancel touch targets if necessary.

TouchTarget predecessor = null;

TouchTarget target = mFirstTouchTarget;

while (target != null) {

final TouchTarget next = target.next;

if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {//執(zhí)行完3.7操作的

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;

}

}

return handled;

}

/**

* Cancels and clears all touch targets.

*/

private void cancelAndClearTouchTargets(MotionEvent event) {

if (mFirstTouchTarget != null) {

boolean syntheticEvent = false;

if (event == null) {

final long now = SystemClock.uptimeMillis();

event = MotionEvent.obtain(now, now,

MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);

event.setSource(InputDevice.SOURCE_TOUCHSCREEN);

syntheticEvent = true;

}

for (TouchTarget target = mFirstTouchTarget; target != null; target = target.next) {

resetCancelNextUpFlag(target.child);

dispatchTransformedTouchEvent(event, true, target.child, target.pointerIdBits);

}

clearTouchTargets();

if (syntheticEvent) {

event.recycle();

}

}

}

//清楚所有的TouchTarget

/**

* Clears all touch targets.

*/

private void clearTouchTargets() {

TouchTarget target = mFirstTouchTarget;

if (target != null) {

do {

TouchTarget next = target.next;

target.recycle();

target = next;

} while (target != null);

mFirstTouchTarget = null;

}

}

//根據(jù)childVie得到TouchTarget

/**

* Gets the touch target for specified child view.

* Returns null if not found.

*/

private TouchTarget getTouchTarget(@NonNull View child) {

// DOWN的時(shí)候因?yàn)?mFirstTouchTarget==null 所以進(jìn)不去 返回的是null

for (TouchTarget target = mFirstTouchTarget; target != null; target = target.next) {

if (target.child == child) {

return target;

}

}

return null;

}

/**

* Transforms a motion event into the coordinate space of a particular child view,

* filters out irrelevant pointer ids, and overrides its action if necessary.

* If child is null, assumes the MotionEvent will be sent to this ViewGroup instead.

*/

private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,

View child, int desiredPointerIdBits) {

//偽代碼

final boolean handled;

if (child == null) {//執(zhí)行View.dispatchTouchEvent 也就是自己的dispatchTouchEvent

handled = super.dispatchTouchEvent(event);

} else {//執(zhí)行child的dispatchTouchEvent

handled = child.dispatchTouchEvent(event);

}

return handled;

}

//添加TouchTarget 并且給mFirstTouchTarget賦值

/**

* Adds a touch target for specified child to the beginning of the list.

* Assumes the target child is not already present.

*/

private TouchTarget addTouchTarget(@NonNull View child, int pointerIdBits) {

final TouchTarget target = TouchTarget.obtain(child, pointerIdBits);

target.next = mFirstTouchTarget;

mFirstTouchTarget = target;

return target;

}

當(dāng)DOWN的時(shí)候,從注釋和方法名可以看出,會(huì)調(diào)用cancelAndClearTouchTargets,然后在調(diào)用clearTouchTargets使mFirstTouchTarget = null用來廢棄上一次的觸摸手勢(shì)。

接著判斷父類需不需要攔截,先通過(mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0來判斷,在這里可以通過getParent().requestDisallowInterceptTouchEvent(boolean disallowIntercept)來改變值,如果上面為判斷為false再通過onInterceptTouchEvent的返回值來確定,這個(gè)函數(shù)默認(rèn)情況下返回false。

檢測(cè)是否為取消事件,如果不是取消、不攔截并且為 DOWN事件的時(shí)候,就會(huì)對(duì)childView一個(gè)反序的for循環(huán)來遍歷,并且執(zhí)行dispatchTransformedTouchEvent操作,這個(gè)操作用來執(zhí)行dispatchTouchEvent,如果childView是null的話將執(zhí)行View.dispatchTouchEvent,也就是自己的dispatchTouchEvent,反之執(zhí)行childView的dispatchTouchEvent,如果執(zhí)行dispatchTransformedTouchEvent返回的值是true那么將會(huì)調(diào)用addTouchTarget()為這個(gè)childView生成一個(gè)TouchTarget并且執(zhí)行mFirstTouchTarget = target將之賦值于mFirstTouchTarget ,然后跳出for循環(huán)遍歷。

判斷操作,首先判斷mFirstTouchTarget是否為null,如果是DOWN事件,不攔截不取消并且dispatchTransformedTouchEvent返回了true,那么將會(huì)不進(jìn)入這個(gè)判斷,如果不是,那么將會(huì)在這執(zhí)行自身的dispatchTouchEvent函數(shù)并且將返回值賦于handled返回。進(jìn)入else語(yǔ)句,在里面將其mFirstTouchTarget進(jìn)行next遍歷,里面的if語(yǔ)句則是DOWN事件下的dispatchTransformedTouchEvent返回true的情況,直接將其賦值,然后返回,里面的else語(yǔ)句則是,調(diào)用dispatchTransformedTouchEvent,然后將其返回值返回。

到這里,ViewGroups事件分發(fā)源碼的流程就分析了,我們根據(jù)這個(gè)來說說上面的場(chǎng)景。

場(chǎng)景一:我們?cè)赥ouchViewGroup的dispatchTouchEvent正常返回super,DOWN事件先觸發(fā)TouchViewGroup的dispatchTouchEvent,然后就執(zhí)行onInterceptTouchEvent是否攔截,onInterceptTouchEvent返回的是super,也就是false,所以就會(huì)通過dispatchTransformedTouchEvent來執(zhí)行TouchView的dispatchTouchEvent,后面就是View的Touch事件分發(fā)了,View流程將會(huì)按照dispatchTouchEvent->onTouchListener - > onTouchEvent的順序執(zhí)行,因?yàn)樵O(shè)置了點(diǎn)擊事件,所以在這里就返回了true,這個(gè)時(shí)候就會(huì)通過addTouchTarget()給mFirstTouchTarget賦值,下面就直接返回了true。然后在MOVE和UP事件的時(shí)候,也是首先執(zhí)行dispatchTouchEvent,調(diào)用super然后調(diào)用onInterceptTouchEvent詢問是否攔截,還是false,但是這里因?yàn)椴皇荄OWN事件,所以就不會(huì)進(jìn)入判斷對(duì)其childView反遍歷,因?yàn)樵贒OWN的時(shí)候mFirstTouchTarget賦值了,所以這時(shí)候進(jìn)入第4步的else語(yǔ)句里面,這時(shí)候就對(duì)其遍歷執(zhí)行dispatchTransformedTouchEvent,也就是dispatchTouchEvent,然后將其返回。

場(chǎng)景2:我們?nèi)∠它c(diǎn)擊事件,那么在DOWN的時(shí)候就不會(huì)給mFirstTouchTarget賦值,這個(gè)時(shí)候?qū)?huì)進(jìn)入第4步的if判斷里面,直接調(diào)用dispatchTransformedTouchEvent,所以事件就不會(huì)有攔截,最終返回false,所以后續(xù)將不會(huì)接受到任何事件

場(chǎng)景3:我們?cè)赥ouchViewGroup的時(shí)候是在onInterceptTouchEvent返回true,所以我們intercepted=true,這時(shí)候就不會(huì)給mFirstTouchTarget賦值,這個(gè)時(shí)候就調(diào)用自身的dispatchTransformedTouchEvent,同樣的返回false,后續(xù)將不會(huì)接受到事件。

通過源碼的角度我們也知道了為什么會(huì)這么執(zhí)行,初步有點(diǎn)模糊,我們需要通過項(xiàng)目慢慢的來完善對(duì)它的認(rèn)知。希望對(duì)大家有所幫助。

總結(jié)

以上是生活随笔為你收集整理的android viewgroup点击变色,Android ViewGroup事件分发的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。