說一下安卓的touch事件分發機制

先從事件的傳遞開始.

一個事件到達界面時, 它的入口是dispatchTouchEvent. 這個方法是視圖處理事件的惟一接口, 全部到達視圖的事件, 都必須通過這個方法.

簡單地說, 系統接收到一個事件, 要丟到一個LinearLayout裏面, 怎麼辦?
直接調這個dispatchTouchEvent, 接收返回的true或者false, 完了.後面的處理就和這個LinearLayout不要緊了.

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

雖然外部只調用dispatchTouchEvent, 可是在這個方法內部, 它本身會根據一系列邏輯調用這些方法.ide

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


父容器的dispatchTouchEvent-->調用內部容器的dispatchTouchEvent-->調用基本控件的dispatchTouchEvent.
這裏的容器就是ViewGroup, 控件就是各類View.



經過這樣的傳遞, 一個複雜的組件對它的上層來講就變得統一了: 我不要去關心你裏面有什麼亂七八糟的基本控件, 怎麼擺放, 怎麼處理. 我分分鐘幾十萬上下, 找一個小小的具體的Button我累不累? 反正我就把事件丟給你, 怎麼處理你來決定.
一樣他的下級也是這個思路, 把事件丟到更下一級, 最終傳達到一個Button讓它響應處理.


這就是責任鏈模式.
可是這樣又產生一個問題: 若是父容器只能起一個傳遞的做用, 事件只能由子控件響應, 那我ScrollView怎麼滑動? ViewPager怎麼切換? 工做不能都壓給最底層的員工吧, 總有些事情是我經理得本身乾的吧, 好比作報表寫工做計劃泡前臺調戲測試之類的..... 咳咳扯遠了.


因此這裏就須要有一個判斷的方法. 一個事件來了, 我本身審覈一下, 這個是個人職責, 那後續的事情我就攬下來, 不往下傳了. 不然就繼續往下傳. 嘿嘿我真是太機智了.


這個判斷的方法就是onInterceptTouchEvent.

 
說到這裏, 要區分 "動做" 和 "事件" 的概念了.


動做就是用戶的一個完整的操做, 好比一個點擊, 一個滑動, 等等.
而事件就是MotionEvent了.
咱們知道全部的事件MotionEvent其實都是瞬態的, 一個事件自己只表明這一瞬間是什麼樣子. 你沒法從單個MotionEvent看出用戶當前是滑動仍是長按, 滑動了多遠, 向左仍是向右. 一個完整的滑動動做是由不斷觸發 ACTION_DOWN, ACTION_MOVE x N, ACTION_UP(或者CANCEL)來組成的. 這些ACTION_DOWN, ACTION_MOVE表明事件的類型(getAction()).


那麼問題又來了.一個單獨的瞬態的ACTION_MOVE, 我怎麼知道這個事件是2秒前的那次DOWN仍是5秒前的那次DOWN帶着的? 我如何判斷一個完整的動做處理完沒有?


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


因此, 一個完整的動做是由一組MotionEvent組成的, 他們擁有共同的downTime. 當視圖接收到具備一個新的downTime的事件時, 它就認爲, 以前的動做已經處理完畢了.


這一塊基本不多有提到過, 平時也用不太上. 可是很重要.
 
 
這個方法的參數雖然是一個事件, 但它實際上攔截的是一個完整的動做. 這就意味着, 若是你在DOWN事件或者某一個MOVE事件返回了true(意味着告訴視圖:"我要攔截了, 這個動做我來處理!"), 那以後的全部事件都不會再繼續往子視圖傳遞了,直到有一個新的動做開始! 到這裏, 咱們能夠試圖解釋一下, 爲何當ViewPager放在ScrollView裏面時, 左右滑動常常變得很困難的緣由.(筒子們能夠試着本身動手寫一個Demo, 你會發現左右滑動切換會變得比在外面困難不少.) 緣由就是ScrollView在接收到MOVE事件時, 會判斷先後兩次事件的y座標之差, 超過必定閾值就會認爲是上下滑動事件, 而後就無情地經過onInterceptTouchEvent接管掉了. 並且這個閾值特別小...... 而咱們在左右滑動的時候, 手指很難保證徹底水平地動做. 稍微有一點角度就產生了Y值的變化, 而後ScrollView大爺的onInterceptTouchEvent就以爲"臥槽這是上下滑動事件啊勞資不能無論啊!!!!".而後果斷返回true. 因而可憐的ViewPager再也沒接收到後續的事件, 也就切換不了了.
相關文章
相關標籤/搜索