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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

说一下安卓的touch事件分发机制

發(fā)布時間:2025/3/15 编程问答 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 说一下安卓的touch事件分发机制 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

先從事件的傳遞開始.

一個事件到達(dá)界面時, 它的入口是dispatchTouchEvent. 這個方法是視圖處理事件的唯一接口, 所有到達(dá)視圖的事件, 都必須經(jīng)過這個方法.

簡單地說, 系統(tǒng)接收到一個事件, 要丟到一個LinearLayout里面, 怎么辦?
直接調(diào)這個dispatchTouchEvent, 接收返回的true或者false, 完了.后面的處理就和這個LinearLayout沒關(guān)系了.

那就有人問了, 那onInterceptTouchEvent, onTouchEvent, onClickListenr, 或者這個LinearLayout里面的Button, 不是還沒處理嗎, 怎么就完了?

雖然外部只調(diào)用dispatchTouchEvent, 但是在這個方法內(nèi)部, 它自己會根據(jù)一系列邏輯調(diào)用這些方法.

件在視圖之間傳遞的順序大概是這樣的:


父容器的dispatchTouchEvent-->調(diào)用內(nèi)部容器的dispatchTouchEvent-->調(diào)用基本控件的dispatchTouchEvent.
這里的容器就是ViewGroup, 控件就是各種View.



通過這樣的傳遞, 一個復(fù)雜的組件對它的上層來說就變得統(tǒng)一了: 我不要去關(guān)心你里面有什么亂七八糟的基本控件, 怎么擺放, 怎么處理. 我分分鐘幾十萬上下, 找一個小小的具體的Button我累不累? 反正我就把事件丟給你, 怎么處理你來決定.
同樣他的下級也是這個思路, 把事件丟到更下一級, 最終傳達(dá)到一個Button讓它響應(yīng)處理.


這就是責(zé)任鏈模式. 但是這樣又產(chǎn)生一個問題: 如果父容器只能起一個傳遞的作用, 事件只能由子控件響應(yīng), 那我ScrollView怎么滑動? ViewPager怎么切換? 工作不能都壓給最底層的員工吧, 總有些事情是我經(jīng)理得自己干的吧, 比如做報表寫工作計劃泡前臺調(diào)戲測試之類的..... 咳咳扯遠(yuǎn)了.


所以這里就需要有一個判斷的方法. 一個事件來了, 我自己審核一下, 這個是我的職責(zé), 那后續(xù)的事情我就攬下來, 不往下傳了. 否則就繼續(xù)往下傳. 嘿嘿我真是太機(jī)智了.


這個判斷的方法就是onInterceptTouchEvent.
說到這里, 要區(qū)分 "動作" 和 "事件" 的概念了.

動作就是用戶的一個完整的操作, 比如一個點(diǎn)擊, 一個滑動, 等等.
而事件就是MotionEvent了.
我們知道所有的事件MotionEvent其實(shí)都是瞬態(tài)的, 一個事件本身只代表這一瞬間是什么樣子. 你無法從單個MotionEvent看出用戶當(dāng)前是滑動還是長按, 滑動了多遠(yuǎn), 向左還是向右. 一個完整的滑動動作是由不斷觸發(fā) ACTION_DOWN, ACTION_MOVE x N, ACTION_UP(或者CANCEL)來組成的. 這些ACTION_DOWN, ACTION_MOVE代表事件的類型(getAction()).


那么問題又來了.一個單獨(dú)的瞬態(tài)的ACTION_MOVE, 我怎么知道這個事件是2秒前的那次DOWN還是5秒前的那次DOWN帶著的? 我如何判斷一個完整的動作處理完沒有?


視圖是通過getDownTime() 這個屬性. 每個動作的一系列事件都有相同的downTime, 也就是DOWN事件的getEventTime這個方法所返回的時間.?


所以, 一個完整的動作是由一組MotionEvent組成的, 他們擁有共同的downTime. 當(dāng)視圖接收到具有一個新的downTime的事件時, 它就認(rèn)為, 之前的動作已經(jīng)處理完畢了.


這一塊基本很少有提到過, 平時也用不太上. 但是很重要.
這個方法的參數(shù)雖然是一個事件, 但它實(shí)際上攔截的是一個完整的動作. 這就意味著, 如果你在DOWN事件或者某一個MOVE事件返回了true(意味著告訴視圖:"我要攔截了, 這個動作我來處理!"), 那之后的所有事件都不會再繼續(xù)往子視圖傳遞了,直到有一個新的動作開始!


到這里, 我們可以試圖解釋一下, 為什么當(dāng)ViewPager放在ScrollView里面時, 左右滑動經(jīng)常變得很困難的原因.(筒子們可以試著自己動手寫一個Demo, 你會發(fā)現(xiàn)左右滑動切換會變得比在外面困難很多.)


原因就是ScrollView在接收到MOVE事件時, 會判斷前后兩次事件的y坐標(biāo)之差, 超過一定閾值就會認(rèn)為是上下滑動事件, 然后就無情地通過onInterceptTouchEvent接管掉了.
而且這個閾值特別小......


而我們在左右滑動的時候, 手指很難保證完全水平地動作. 稍微有一點(diǎn)角度就產(chǎn)生了Y值的變化, 然后ScrollView大爺?shù)膐nInterceptTouchEvent就覺得"臥槽這是上下滑動事件啊勞資不能不管啊!!!!".然后果斷返回true.
于是可憐的ViewPager再也沒接收到后續(xù)的事件, 也就切換不了了.

轉(zhuǎn)載于:https://www.cnblogs.com/erry/p/4283461.html

總結(jié)

以上是生活随笔為你收集整理的说一下安卓的touch事件分发机制的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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