五月天青色头像情侣网名,国产亚洲av片在线观看18女人,黑人巨茎大战俄罗斯美女,扒下她的小内裤打屁股

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

app開發(fā)觸摸事件的ACTION_CANCEL怎么產(chǎn)生-討厭的android觸摸面試題

2023-09-09 16:40 作者:千里馬學(xué)框架  | 我要投稿

hi,粉絲朋友!?

大家對于MotionEvent.ACTION_CANCEL這個(gè)cancel事件是不是感覺又熟悉又陌生,熟悉是因?yàn)榻?jīng)常在onTouch識別觸摸事件時(shí)候會把它和ACTION_UP放在一塊處理,基本停留在字面意思理解為 “”取消“”

對應(yīng)的文章視頻講解:https://www.bilibili.com/video/BV1Ti4y1D7Pq/


更多android 干貨知識分享請+W:androidframework007


ACTION_CANCEL觸發(fā)場景和原因:

customTextView.setOnTouchListener(new?View.OnTouchListener()?{
????@Override
????public?boolean?onTouch(View?view,?MotionEvent?motionEvent)?{
????????Log.i("test2","?onTouch?motionEvent?=?"?+?motionEvent);
????????if?(motionEvent.getAction()?==?MotionEvent.ACTION_CANCEL?||?motionEvent.getAction()?==?MotionEvent.ACTION_UP?)?{
????????????Log.i("test2","?onTouch?ACTION_CANCEL?=?"?,new?Exception());
????????}
????????return?true;
????}
});

所以這里本節(jié)課就來帶大家深入理解這里ACTION_CANCEL

首先我們來分析應(yīng)用觸摸最常見的ACTION_CANCEL情況:

在這里插入圖片描述

這個(gè)就是我們常見的一個(gè)父布局MyLayout,它裝載了2個(gè)子控件textview1和textview2.假設(shè)一個(gè)觸摸事件到來,我們知道觸摸事件的傳遞順序就是:父布局 ?-- 》 子布局 這樣的一個(gè)順序,也就是其實(shí)事件父布局是具有完全的決策權(quán)利來是否給子布局,可以通過方法onInterceptTouchEvent。 接下來我們又來看看MotionEvent,一個(gè)正常完整觸摸應(yīng)該是怎么個(gè)順序呢? ACTION_DOWN -- > ACTION_MOVE --> ACTION_UP 所以說我們控件正常事件處理就是最少要有DOWN --》UP兩個(gè)事件,才代表事件介紹,那么你會問如果只有DOWN,和MOVE是否可以呢?答案:當(dāng)然是不可以的 為啥呢? 大家可以想一下這樣一個(gè)場景,你是一個(gè)按鈕,來了觸摸事件DOWN了后,你把按鈕變成selected狀態(tài)了,你本來一直等值來個(gè)UP事件來變回正常狀態(tài),如果系統(tǒng)發(fā)生依次你沒有收到UP會怎么樣呢?那就是你的應(yīng)用按鈕就永遠(yuǎn)處于選中狀態(tài)無法取消,一直到進(jìn)程關(guān)閉(當(dāng)然說是正常你沒有特別處理情況)。

所以有了以上基礎(chǔ)后,大家就知道有了DOWN事件一般都要有UP事件才算完整,但是有一些場景他就是可能收到了DOWN,后面收不到UP了怎么辦? 比如看如下例子:

????@Override
????public?boolean?onInterceptTouchEvent(MotionEvent?ev)?{
????????Log.i("test2","onInterceptTouchEvent?ev?=?"?+?ev);
????????if?(ev.getAction()?==?MotionEvent.ACTION_MOVE?)?{//我們不攔截DOWN事件,但是攔截MOVE事件,父布局一攔截,子控件就會收到ACTION_CANCEL
????????????return?true;
????????}
????????return?super.onInterceptTouchEvent(ev);
????}

這種情況我們父布局只并沒有攔截DOWN事件,所以DOWN傳遞給你textview1,但是因?yàn)樵贛OVE時(shí)候我們父布局?jǐn)r截了,即說明事件不再傳遞給子控件了textview1,那么這個(gè)是不是就是textview1收到了DOWN,但是收不到UP情況,不完整了,那該怎么辦?

這個(gè)時(shí)候其實(shí)就是今天重點(diǎn)介紹的ACTION_CANCEL出廠,他就是來幫忙解決上面的因?yàn)楦覆季种虚g進(jìn)行了觸摸事件攔截,但是子布局又要一個(gè)完整觸摸過程,那么就需要傳遞一個(gè)觸摸事件給子控件,那么傳遞什么合適? 大家肯定會想U(xiǎn)P最合適,UP不就可以了?但是你要想想用戶還沒有UP???如果傳遞了UP是不是也可能會有問題,所以這時(shí)候就是傳遞ACTION_CANCEL,它代表是取消,即代表這個(gè)觸摸事件到此被取消結(jié)束了??丶盏叫枰约鹤鰧?yīng)的掃尾工作,保證事件完整。

上面我們已經(jīng)對ACTION_CANCEL觸發(fā)場景和原因已經(jīng)清楚,接下來看看源碼是怎么處理的:

ACTION_CANCEL出現(xiàn)源碼分析

app代碼: layout.xml

?????android:layout_width="match_parent"
????????android:layout_height="wrap_content"
????????android:orientation="vertical"
????????android:paddingTop="100dp"
????????>
????????<TextView
????????????android:id="@+id/custom_text"
????????????android:layout_width="wrap_content"
????????????android:layout_height="wrap_content"
????????????android:text="Hello?CustomLayout?!"
????????????>
</TextView>

????</com.example.anrdemo.CustomLayout>

代碼端對onTouch的事件進(jìn)行監(jiān)聽:

???TextView?customTextView?=?(TextView)findViewById(R.id.custom_text);
????????customTextView.setOnTouchListener(new?View.OnTouchListener()?{
????????????@Override
????????????public?boolean?onTouch(View?view,?MotionEvent?motionEvent)?{
????????????????Log.i("test2","?onTouch?motionEvent?=?"?+?motionEvent);
????????????????if?(motionEvent.getAction()?==?MotionEvent.ACTION_CANCEL?||?motionEvent.getAction()?==?MotionEvent.ACTION_UP?)?{
????????????????//變成了CANCEL后打印一下堆棧,追蹤框架哪里進(jìn)行了改變
????????????????????Log.i("test2","?onTouch?ACTION_CANCEL?=?"?,new?Exception());
????????????????}
????????????????return?true;
????????????}
????????});
2021-11-27?13:50:06.911?7010-7010/com.example.anrdemo?I/test2:??onTouch?ACTION_CANCEL?=?
????java.lang.Exception
????????at?com.example.anrdemo.MainActivity$2.onTouch(MainActivity.java:46)
????????at?android.view.View.dispatchTouchEvent(View.java:13949)
????????at?android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3030)
????????at?android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2755)
????????at?android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3060)
????????at?android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2755)
????????at?android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3060)
????????at?android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2755)
????????at?android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3060)
????????at?android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2755)
????????at?android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3060)
????????at?android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2755)
????????at?android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3060)
????????at?android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2755)
????????at?android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3060)
????????at?android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2755)
????????at?com.android.internal.policy.DecorView.superDispatchTouchEvent(DecorView.java:465)
????????at?com.android.internal.policy.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1849)
????????at?android.app.Activity.dispatchTouchEvent(Activity.java:4011)
????????at?com.example.anrdemo.MainActivity.dispatchTouchEvent(MainActivity.java:72)
????????at?androidx.appcompat.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:69)
????????at?androidx.appcompat.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:69)
????????at?com.android.internal.policy.DecorView.dispatchTouchEvent(DecorView.java:423)
????????at?android.view.View.dispatchPointerEvent(View.java:14212)
????????at?android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:5652)
????????at?android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:5455)
????????at?android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4958)
????????at?android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:5011)
????????at?android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4977)
????????at?android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:5117)
????????at?android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4985)
????????at?android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:5174)
????????at?android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4958)
????????at?android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:5011)
????????at?android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4977)
????????at?android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4985)
????????at?android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4958)
????????at?android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:7675)
????????at?android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:7644)
????????at?android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:7605)
????????at?android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:7800)
????????at?android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:188)
????????at?android.view.InputEventReceiver.nativeConsumeBatchedInputEvents(Native?Method)
????????at?android.view.InputEventReceiver.consumeBatchedInputEvents(InputEventReceiver.java:178)
????????at?android.view.ViewRootImpl.doConsumeBatchedInput(ViewRootImpl.java:7751)
????????at?android.view.ViewRootImpl$ConsumeBatchedInputRunnable.run(ViewRootImpl.java:7824)
????????at?android.view.Choreographer$CallbackRecord.run(Choreographer.java:967)
????????at?android.view.Choreographer.doCallbacks(Choreographer.java:791)
????????at?android.view.Choreographer.doFrame(Choreographer.java:719)
????????at?android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:952)
????????at?android.os.Handler.handleCallback(Handler.java:883)
????????at?android.os.Handler.dispatchMessage(Handler.java:100)

這里就打印出來了框架調(diào)用到onTouch中MotionEvent變成CANCEL的流程,方便我們進(jìn)行源碼分析。 具體大家可以自己取追蹤,這里我這邊列出結(jié)果: base/core/java/android/view/ViewGroup.java


????????????//?Check?for?interception.
????????????final?boolean?intercepted;
????????????if?(actionMasked?==?MotionEvent.ACTION_DOWN
????????????????????||?mFirstTouchTarget?!=?null)?{
????????????????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;
????????????????}
????????????}?

這里onInterceptTouchEvent會調(diào)用到我們CustomLayout的onInterceptTouchEvent,我們識別到了如果MOVE就return true,所以intercepted這個(gè)時(shí)候也是true。

final?boolean?cancelChild?=?resetCancelNextUpFlag(target.child)
????????????????????????????????||?intercepted;
????????????????????????if?(dispatchTransformedTouchEvent(ev,?cancelChild,
????????????????????????????????target.child,?target.pointerIdBits))

這里cancelChild就變成了true,所以

private?boolean?dispatchTransformedTouchEvent(MotionEvent?event,?boolean?cancel,
????????????View?child,?int?desiredPointerIdBits)
?{
????????final?boolean?handled;

????????final?int?oldAction?=?event.getAction();
????????if?(cancel?||?oldAction?==?MotionEvent.ACTION_CANCEL)?{//根據(jù)前面cancelChild變成了CANCEL
????????????event.setAction(MotionEvent.ACTION_CANCEL);
????????????if?(child?==?null)?{
????????????????handled?=?super.dispatchTouchEvent(event);
????????????}?else?{
????????????????handled?=?child.dispatchTouchEvent(event);
????????????}
????????????event.setAction(oldAction);
????????????return?handled;
????????}
//---省略部分
}
????????
從以上可以看出,結(jié)合我們Input專題學(xué)習(xí)知識,我們知道觸摸事件InputDispatcher傳遞給App實(shí)際還是ACTION_MOVE,但是app進(jìn)程ViewGroup的策略把事件變成了ACTION_CANCEL來保證事件的完整性。 總結(jié)流程圖:

在這里插入圖片描述




app開發(fā)觸摸事件的ACTION_CANCEL怎么產(chǎn)生-討厭的android觸摸面試題的評論 (共 條)

分享到微博請遵守國家法律
渑池县| 会泽县| 宜都市| 新密市| 民丰县| 南京市| 太谷县| 彩票| 闵行区| 河间市| 莲花县| 嘉荫县| 宁晋县| 邳州市| 广安市| 鲁甸县| 佛坪县| 巴马| 漾濞| 葵青区| 镇宁| 公主岭市| 霍城县| 察哈| 台南市| 金阳县| 华宁县| 稻城县| 四川省| 孝感市| 崇仁县| 霍城县| 额济纳旗| 郓城县| 扬州市| 信丰县| 巴里| 休宁县| 贺州市| 明光市| 邛崃市|