说一下安卓的touch事件分发机制
生活随笔
收集整理的這篇文章主要介紹了
说一下安卓的touch事件分发机制
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
先從事件的傳遞開始.
一個事件到達界面時, 它的入口是dispatchTouchEvent. 這個方法是視圖處理事件的唯一接口, 所有到達視圖的事件, 都必須經過這個方法.
簡單地說, 系統接收到一個事件, 要丟到一個LinearLayout里面, 怎么辦?
直接調這個dispatchTouchEvent, 接收返回的true或者false, 完了.后面的處理就和這個LinearLayout沒關系了.
那就有人問了, 那onInterceptTouchEvent, onTouchEvent, onClickListenr, 或者這個LinearLayout里面的Button, 不是還沒處理嗎, 怎么就完了?
雖然外部只調用dispatchTouchEvent, 但是在這個方法內部, 它自己會根據一系列邏輯調用這些方法.
父容器的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再也沒接收到后續的事件, 也就切換不了了.
轉載于:https://www.cnblogs.com/erry/p/4283461.html
總結
以上是生活随笔為你收集整理的说一下安卓的touch事件分发机制的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: javascript闭包原理
- 下一篇: 生产者/消费者模式(一)