Disclaimer: ciò che segue è principalmente il risultato della mia sperimentazione in React Native 0.50. Nella ScrollViewdocumentazione 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 ScrollViewripresa evente 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 scrollEventThrottlee al massimo una volta per fotogramma quando scrollEventThrottle={16}. Se l'utente rilascia la visualizzazione a scorrimento mentre ha abbastanza slancio per planare, il onScrollconduttore 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.scrollEventThrottleonScroll
L'impostazione ha un costo in termini di prestazioni scrollEventThrottle={16}che può essere ridotto impostandolo su un numero maggiore. Tuttavia, ciò significa che onScrollnon 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 ScrollViewframe di a causa della rotazione, e non si desidera accettare la penalizzazione delle prestazioni su Android dall'impostazione scrollEventThrottlea 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 onScrollgestore 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 scrollEventThrottlee fornire in aggiunta un onScrollEndDraggestore:
<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 onContentSizeChangee onLayouttenere 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.