前言
本文旨在介紹React Native ScrollView官方文檔中未提及的滾動事件API,著重介紹如何從物理學角度理解onMomentumScrollBegin 和onMomentumScrollEnd函數。
至于官方文檔中為何不提及這些API,個人理解是目前文檔也在不斷更新,文檔還未完善。亦或是我打開的姿勢不對?希望知道的朋友能科普下,解鎖新的姿勢。
ScrollView簡介
一個包裝了平臺的ScrollView(滾動視圖)的組件,同時還集成了觸摸鎖定的“響應者”系統。
記住ScrollView必須有一個確定的高度才能正常工作,因為它實際上所做的就是將一系列不確定高度的子組件裝進一個確定高度的容器(通過滾動操作)。要給一個ScrollView確定一個高度的話,要么直接給它設置高度(不建議),要么確定所有的父容器都已經綁定了高度。在視圖棧的任意一個位置忘記使用{flex:1}都會導致錯誤,你可以使用元素查看器來查找問題的原因。
ScrollView內部的其他響應者尚無法阻止ScrollView本身成為響應者。
官方文檔介紹的API
官方文檔中提及了三個與事件回調相關的API,如下所示:
官方文檔未介紹的API
此處只列出ScrollView特有的事件回調API,關于“響應者系統”的回調API一下就不列出了。
API | Description |
---|---|
onTouchStart | 按下屏幕時觸發 |
onTouchMove | 移動時觸發,實際上按住不動也會觸發 |
onTouchEnd | 手指離開屏幕時觸發,Android測試當有拖曳行為時會調用onScrollEndDrag來代替之;當無拖曳行為時,手指離開就會觸發 |
onScrollBeginDrag | 開始拖動時觸發,滾動開始的標志 |
onScroll | 滾動過程中調用,一幀最多調用一次 |
onScrollEndDrag | 拖曳結束時調用,頂替onTouchEnd |
onMomentumScrollBegin | 手指離開屏幕時調用(瞬時沖量滑動的開始) |
onMomentumScrollEnd | 滾動結束時調用(瞬時沖量滑動的結束) |
起初很不理解最后倆個方法的描述,網上一查資料,解釋為“一幀滾動的開始結束”,“幀滾動”是什么鬼?一臉懵逼,我拖曳的時候畫面不是一直在滾動嗎?意思會調用好幾次?百度、google無果,只能一臉懵逼的自己寫Demo驗證了。
Momentum一詞指物理學中動量,再解釋之前,我們先回顧下高中所學的物理知識。
動量定理:
瞬時沖量:極短時間內力F產生的沖量,簡單點就理解為物體的速度會突變,舉個例子就是你給一個靜止的物體,施加一個瞬時沖量,那瞬間,物體的速度會從0突變到另外一個值,而位移未曾改變。
結論:這組函數是用于響應你手指在離開屏幕那一剎那(極短時間),對物體在滑動反方向上所施加力的作用效果,這時會產生一個瞬時沖量,至使物體速度突變,之后的滑動過程就是一個減速運動至速度為零(ScrollView內部會模擬產生一個摩擦力)。
這就是為什么在ScrollView的實際操作當中,當我們用力滑動一小截,ScrollView就會連翻好幾頁的原因。
簡而言之:
onMomentumScrollBegin會在你手指離開屏幕時調用,不過在此之前會先調用onScrollDragEnd,onMomentumScrollEnd會在滑動結束時調用。
Demo測試驗證
測試情景一:
手指按住,不移動(持續1-2s),然后離開屏幕,測試結果如下如所示:
可見onTouchMove在測試期間共調用了35次,并不是如網上所言在移動時候調用,而是在onTouchStart后就會調用,手指離開屏幕就會調用onTouchEnd結束事件響應。
注意,onTouchMove傳進來的nativeEvent并沒有contentOffset屬性(圖片相對ScrollView容器的滑動偏移量)如圖-4所示,這也從另外一個方面說明它不是在移動的時候調用。
測試情景二:
手指按住屏幕,慢慢的拖動一段距離,再最后要離開屏幕時,手指往滑動反方向用力,測試結果如下所示,圖中數字表示滑動方向的偏移量:
上面說到onTouchMove并不是在滑動時調用,那么滑動開始回調API是誰呢?聰明的你肯定想到了,沒錯就是onScrollBeginDrag,代表滑動的開始。該函數接收的nativeEvent才包含了contentOffset屬性,如圖-5所示。
onScroll就是在滑動的過程中會調用。
重點來了,
在你手指離開屏幕時,會先調用onScrollEndDrag,表示拖動結束,接下來,就如上面我們分析的一樣,根據你手指離開屏幕時所施加的力,計算這個瞬時沖量該讓圖片滑動多少距離。依次調用onMomentumScrollBegin,onScroll,onMomentumScrollEnd。
測試代碼就不上了,太長了,寫起來也很簡單。
最后,由于本人水平有限,第一次寫文章,文中難免有不妥之處,還請多多體諒。