React Native — ScrollView props

葉明哲 (Brian Yeh)
10 min readJan 3, 2021

--

來幫 ScrollView 的所有 props 寫範例程式

Photo by Henry & Co. on Unsplash

範例程式在此:https://snack.expo.io/@tp26610/scrollviewprops

範例程式無法在 Snack 的 Web 上運作,似乎是 Snack 的 Web 平台在最外層有自動加上 ScrollView,造成範例程式內的 ScrollView 無法正常運作。建議用實體機測試會比較正常。

本來是想用這篇貼文把 ScrollView 的所有 props 都介紹完,但因為是邊實作邊把過程寫下來,前進速度比較緩慢。想固定一個月產一篇文章的狀況下只好先把已經實作完畢的 props 發出來,其他尚未介紹到的 props 就留給下一篇文章啦!就讓我們開始吧:

No props (沒有設定任何 props)

如果 ScrollView 沒有設定任何 props ,預設會是全螢幕、有垂直方向捲軸、右邊有 scrollbar。中間範例程式有實作一個螢幕有兩個 ScrollView ,設定 style 中的 flex 無效,好像會強制被設定成 flex: 1,兩個 ScrollView 剛好各自占到畫面一半。

alwaysBouncesHorizontal (iOS)

預設為 false,如果設定為 true 的話,就會有反彈的效果。如果設定 horizontaltrue,則 alwaysBouncesHorizontal 就會變成 true

反彈效果如下動畫:

alwaysHorizontalBounces is true

alwaysBouncesVertical (iOS)

因為預設 ScrollView 是垂直方向,此時設定 alwaysBouncesVertical 無效,所以要測試此 prop 時,必須要先把 ScrollView 方向變成水平方向,也就是要加上 horizontal prop。horizontalfalse 時,vertical bounces 效果會一直存在。

設定成功後效果如下動畫:

alwaysVerticalBounces and horizontal are true

automaticallyAdjustContentInsets (iOS)

預設是 true,實測 true / false 都沒什麼特別的效果,查了一下 Apple 官網文件,發現已經 deprecated。

bounces (iOS)

預設是 true ,滑動超出之後會有反彈動畫。設定成 false 後,即使 alwaysBouncesHorizontalalwaysBouncesVertical 設定為 true 也無法有反彈效果。

bouncesZoom (iOS)

不管設定 true / false 測試起來皆無效果

canCancelContentTouches (iOS)

設定為 true 時會優先響應 ScrollView 的觸控事件。

在 ScrollView 裡面放了一個 Pressable 元件來測試,canCancelContentTouchestrue 時,手指壓下 Pressable 不放,只要手指有上下滑動,就會讓 ScrollView 上下滑動。當 canCancelContentTouchesfasle 時,觸控事件只會由 Pressable 元件響應,手指壓住 Pressable 上下滑動,不會讓 ScrollView 滑動。

centerContent (iOS)

設定 true 時,children 會在 ScrollView 的正中間,範例程式寫了 switch 動態調整此 prop,測試起來發現按下開關後,有時會需要滑動 ScrollView 才會讓 Pressable 跳到正確的位置。

contentContainerStyle

可以把 ScrollView 想成是兩層 View,外層 View 有捲軸,預設會是全螢幕。內層 View 預設 children 的長寬。ScrollView 的 style 是設定外層 View 的樣式,contentContainerStyle 是用來設定內層 View 的樣式。

ScrollView 的 style height 設定之後不會變矮,一定會是全螢幕。如果想要讓 content 變短,就必須設定 contentContainerStyle

contentInset (iOS)

ScrollView 的向外延展區,預設畫面會顯示在內層 View 的區域 (圖中的 ContentView),向外延展區也都算是 ScrollView 可滑動的範圍。但對於卷軸的位置來說是 margin 的效果,水平和垂直卷軸會往內縮。

contentInsetAdjustmentBehavior (iOS)

在 iPhone 8 測試起來沒什麼不同,看了官方文件描述,此屬性主要是和 safe area 的互動,可能拿 iPhone X 以上來測試就會有差了,等我悟出差異再來補充內容。

contentOffset (iOS)

ScrollView 的初始位址,範例程式中的每個 itemView 高度為 44,contentOffset 設定 {x: 440} 會定到第 10 個 item 的位置。

decelerationRate

以前物理課學過加速度,deceleration 是加速度的反意,也就是減速度。此屬性用來設定使用者滑動時,手指離開 ScrollView 後的減速度,數字愈大減速愈慢。測試設定 0 ,手指離開 ScrollView 後,幾乎馬上停止滑動。另外也可填入字串 fast (馬上停止) 或 normal (會再滑一陣子)

directionalLockEnabled (iOS)

假設 ScrollView 可以上下左右滑,此 prop 設定為 true 時,手指壓住螢幕垂直滑動時,會把水平滑動關閉,待使用者手指放開,停止垂直滑動後才可以水平滑動。反之亦然,在水平滑動的過程中無法垂直滑動。

fadingEdgeLength (Android)

假設設定垂直方向,如果 ScrollView 的下面或上面有更多 ItemView 可以顯示時,會有淡色效果,愈接近上面或下面邊界的 ItemView 顏色會愈淡。如果上面或下面已經到底,不能滑動的話就不會有淡出效果。有淡出效果就代表可以繼續滑動。

horizontal

ScrollView 的滑動方向,預設是垂直方向,把此 prop 設定為 true 就會變成水平方向。

indicatorStyle (iOS)

捲軸的顏色,此欄位可填入字串 defaultblackwhitedefaultblack 效果一樣,都是黑色。

invertStickyHeaders + stickyHeaderIndices

stickyHeaderIndices 可填入一個 array,範例程式是填入 [0, 15, 30] ,代表 index 0 滑過 ScrollView 最上方時,會卡在 ScrollView 的最上方,而 index 15 滑過時,會取代 index 0 卡在最上方

invertStickyHeaders 設定為 true 時,會變成滑到該 index 時,children 卡在最下方。

範例程式寫了一個開關來動態控制 invertStickyHeaderstruefalse ,這邊遇到一個問題:當初始值設定 false 時,之後透過開關改成 true,會無效。預設值設定成 true 就不會有此問題。

此 prop 在水平模式時無效

keyboardDismissMode

用來設定讓鍵盤消失的方式,可填入: noneon-draginteractive

  • none: 滑動 ScrollView 時,鍵盤不會消失
  • on-drag: 滑動 ScrollView 時,讓鍵盤消失。測試 Android 無效
  • interactive (iOS): 互動方式讓鍵盤消失,但我試不出來

keyboardShouldPersistTaps

用來設定點擊 ScrollView 時,鍵盤處理該點擊的互動方式,可填入以下字串:

  • never (預設值): 點擊 ScrollView 的任何區域會使鍵盤消失,且在 ScrollView 裡面的 Component 不會收到這次的點擊事件
  • always : 點擊 ScrollView 不會使鍵盤消失,在 ScrollView 裡的 Component 會收到此點擊事件
  • handled : 點擊 ScrollView 會使鍵盤消失,當 ScrollView 裡的 Component 有處理該點擊事件時,鍵盤會保持顯示。

onMomentumScrollBegin、onMomentumScrollEnd

當 ScrollView 開始滑行時,會觸發 onMomentumScrollBegin ,當 ScrollView 停止滑行時,會觸發 onMomentumScrollEnd

onScrollBeginDrag、onScrollEndDrag

當手指壓著 ScrollView 且開始滑動時,會觸發 onScrollBeginDrag。當手指放開螢幕時,會觸發 onScrollEndDrag

onScroll

ScrollView 滑動中會不斷觸發 onScroll ,此 function 會回傳 event 物件,官網文件給的資料格式如下 (所有欄位的型態皆為 number):

{
nativeEvent: {
contentInset: {bottom, left, right, top},
contentOffset: {x, y},
contentSize: {height, width},
layoutMeasurement: {height, width},
zoomScale
}
}

iOS 觸發 onScroll 的時機和 onMomentumScrollBeginonMomentumScrollEnd 的時機點一致,如果想要更即時的滑動資訊,可以搭配 scrollEventThrottle 設定 onScroll 的觸發頻率。

Android 會頻繁地觸發 onScroll ,且在該 function 回傳的 event 中還有額外帶一些參數:

{
...
responderIgnoreScroll: true,
velocity: {
y: 0.04651162773370743,
x: 0
},
target: 7519
}

onScrollToTop (iOS)

先把 ScrollView 滑動到非置頂的狀態,此時點擊螢幕最上方的系統狀態列 (StatusBar),ScrollView 會滑回置頂狀態且觸發 onScrollToTop ,視覺上的感受是置頂約 500 毫秒後才觸發 onScrollToTop

--

--

葉明哲 (Brian Yeh)
葉明哲 (Brian Yeh)

Written by 葉明哲 (Brian Yeh)

沒事就愛寫點小程式,夢想能建立一個永續的軟體團隊

No responses yet