Disclaimer: ciò che segue è principalmente il risultato della mia sperimentazione in React Native 0.50. Nella ScrollView
documentazione mancano attualmente molte delle informazioni trattate di seguito; per esempio onScrollEndDrag
è completamente priva di documenti. Poiché qui tutto si basa su comportamenti non documentati, purtroppo non posso promettere che queste informazioni rimarranno corrette per un anno o anche un mese da oggi.
Inoltre, tutto ciò che segue presuppone una visualizzazione a scorrimento puramente verticale di cui siamo interessati all'offset y ; si spera che tradurre in x offset, se necessario, sia un esercizio facile per il lettore.
Vari gestori di eventi su una ScrollView
ripresa event
e consentono di ottenere la posizione di scorrimento corrente tramite event.nativeEvent.contentOffset.y
. Alcuni di questi gestori hanno un comportamento leggermente diverso tra Android e iOS, come descritto di seguito.
Su Android
Spara ogni fotogramma mentre l'utente sta scorrendo, su ogni fotogramma mentre la vista a scorrimento scorre dopo che l'utente l'ha rilasciata, sul fotogramma finale quando la vista a scorrimento si ferma, e anche ogni volta che l'offset della vista a scorrimento cambia a causa del suo fotogramma cambiando (ad esempio a causa della rotazione da orizzontale a verticale).
Su iOS
Si attiva mentre l'utente sta trascinando o mentre la visualizzazione di scorrimento scorre, a una frequenza determinata da scrollEventThrottle
e al massimo una volta per fotogramma quando scrollEventThrottle={16}
. Se l'utente rilascia la visualizzazione a scorrimento mentre ha abbastanza slancio per planare, il onScroll
conduttore scatterà anche quando si ferma dopo la planata. Tuttavia, se l'utente trascina e quindi rilascia la visualizzazione a scorrimento mentre è ferma, nononScroll
è garantito che si attivi per la posizione finale a meno che non sia stato impostato in modo tale da attivare ogni fotogramma di scorrimento.scrollEventThrottle
onScroll
L'impostazione ha un costo in termini di prestazioni scrollEventThrottle={16}
che può essere ridotto impostandolo su un numero maggiore. Tuttavia, ciò significa che onScroll
non verrà attivato ogni fotogramma.
Si attiva quando la visualizzazione a scorrimento si ferma dopo lo scorrimento. Non si attiva affatto se l'utente rilascia la visualizzazione a scorrimento mentre è ferma in modo che non scivoli.
onScrollEndDrag
Si attiva quando l'utente smette di trascinare la visualizzazione a scorrimento, indipendentemente dal fatto che la visualizzazione a scorrimento sia lasciata ferma o inizi a scorrere.
Date queste differenze di comportamento, il modo migliore per tenere traccia dell'offset dipende dalle circostanze specifiche. Nel caso più complicato (è necessario supportare Android e iOS, inclusa la gestione delle modifiche nel ScrollView
frame di a causa della rotazione, e non si desidera accettare la penalizzazione delle prestazioni su Android dall'impostazione scrollEventThrottle
a 16), e è necessario gestire cambia anche il contenuto nella visualizzazione a scorrimento, quindi è un vero casino.
Il caso più semplice è se devi solo gestire Android; basta usare onScroll
:
<ScrollView
onScroll={event => {
this.yOffset = event.nativeEvent.contentOffset.y
}}
>
Per supportare ulteriormente iOS, se sei felice di attivare il onScroll
gestore ogni frame e accettare le implicazioni sulle prestazioni di questo, e se non hai bisogno di gestire i cambiamenti di frame, allora è solo un po 'più complicato:
<ScrollView
onScroll={event => {
this.yOffset = event.nativeEvent.contentOffset.y
}}
scrollEventThrottle={16}
>
Per ridurre il sovraccarico delle prestazioni su iOS pur continuando a garantire che registriamo qualsiasi posizione su cui si stabilisce la visualizzazione a scorrimento, possiamo aumentare scrollEventThrottle
e fornire in aggiunta un onScrollEndDrag
gestore:
<ScrollView
onScroll={event => {
this.yOffset = event.nativeEvent.contentOffset.y
}}
onScrollEndDrag={event => {
this.yOffset = event.nativeEvent.contentOffset.y
}}
scrollEventThrottle={160}
>
Ma se vogliamo gestire le modifiche al frame (ad es. Perché permettiamo al dispositivo di essere ruotato, cambiando l'altezza disponibile per il frame della visualizzazione a scorrimento) e / o le modifiche al contenuto, allora dobbiamo implementarli entrambi onContentSizeChange
e onLayout
tenere traccia dell'altezza di entrambi il frame della visualizzazione a scorrimento e il suo contenuto, quindi calcolare continuamente l' offset massimo possibile e dedurre quando l'offset è stato ridotto automaticamente a causa di una modifica della dimensione del frame o del contenuto:
<ScrollView
onLayout={event => {
this.frameHeight = event.nativeEvent.layout.height;
const maxOffset = this.contentHeight - this.frameHeight;
if (maxOffset < this.yOffset) {
this.yOffset = maxOffset;
}
}}
onContentSizeChange={(contentWidth, contentHeight) => {
this.contentHeight = contentHeight;
const maxOffset = this.contentHeight - this.frameHeight;
if (maxOffset < this.yOffset) {
this.yOffset = maxOffset;
}
}}
onScroll={event => {
this.yOffset = event.nativeEvent.contentOffset.y;
}}
onScrollEndDrag={event => {
this.yOffset = event.nativeEvent.contentOffset.y;
}}
scrollEventThrottle={160}
>
Sì, è piuttosto orribile. Inoltre, non sono sicuro al 100% che funzionerà sempre correttamente nei casi in cui modifichi simultaneamente la dimensione del frame e del contenuto della visualizzazione a scorrimento. Ma è il meglio che riesco a trovare e fino a quando questa funzione non viene aggiunta all'interno del framework stesso , penso che questo sia il meglio che chiunque possa fare.