Descargo de responsabilidad: lo que sigue es principalmente el resultado de mi propia experimentación en React Native 0.50. Actualmente, a la ScrollViewdocumentación le falta mucha de la información que se describe a continuación; por ejemplo, onScrollEndDragestá completamente indocumentado. Dado que todo aquí se basa en un comportamiento indocumentado, desafortunadamente no puedo prometer que esta información seguirá siendo correcta dentro de un año o incluso un mes.
Además, todo lo que se muestra a continuación asume una vista de desplazamiento puramente vertical cuyo desplazamiento y nos interesa; traducir ax compensaciones, si es necesario, es con suerte un ejercicio fácil para el lector.
Varios controladores de eventos en una ScrollViewtoma eventy le permiten obtener la posición de desplazamiento actual a través de event.nativeEvent.contentOffset.y. Algunos de estos controladores tienen un comportamiento ligeramente diferente entre Android e iOS, como se detalla a continuación.
En Android
Dispara cada fotograma mientras el usuario se desplaza, en cada fotograma mientras la vista de desplazamiento se desliza después de que el usuario la suelta, en el fotograma final cuando la vista de desplazamiento se detiene, y también siempre que el desplazamiento de la vista de desplazamiento cambia como resultado de su fotograma cambiando (por ejemplo, debido a la rotación de paisaje a retrato).
En iOS
Se dispara mientras el usuario arrastra o mientras la vista de desplazamiento se desliza, a una frecuencia determinada por scrollEventThrottley como máximo una vez por cuadro cuando scrollEventThrottle={16}. Si el usuario suelta la vista de desplazamiento mientras tiene suficiente impulso para planear, el onScrollcontrolador también disparará cuando se detenga después de planear. Sin embargo, si el usuario arrastra y suelta el punto de vista de desplazamiento mientras está parado, onScrollestá no garantizada al fuego para la posición final a menos que scrollEventThrottlese ha establecido de tal manera que onScrolllos incendios cada fotograma de desplazamiento.
Hay un costo de rendimiento en la configuración scrollEventThrottle={16}que se puede reducir configurándolo en un número mayor. Sin embargo, esto significa que onScrollno disparará todos los fotogramas.
Se dispara cuando la vista de desplazamiento se detiene después de planear. No dispara en absoluto si el usuario suelta la vista de desplazamiento mientras está estacionaria para que no se deslice.
onScrollEndDrag
Se dispara cuando el usuario deja de arrastrar la vista de desplazamiento, independientemente de si la vista de desplazamiento se deja estacionaria o comienza a deslizarse.
Dadas estas diferencias de comportamiento, la mejor manera de realizar un seguimiento de la compensación depende de sus circunstancias precisas. En el caso más complicado (necesita ser compatible con Android e iOS, incluido el manejo de cambios en el ScrollViewmarco debido a la rotación, y no desea aceptar la penalización de rendimiento en Android de la configuración scrollEventThrottlea 16), y debe manejar También cambia el contenido en la vista de desplazamiento, entonces es un maldito desastre.
El caso más simple es si solo necesita manejar Android; solo usa onScroll:
<ScrollView
onScroll={event => {
this.yOffset = event.nativeEvent.contentOffset.y
}}
>
Para admitir adicionalmente iOS, si está contento de despedir al onScrollcontrolador en cada cuadro y acepta las implicaciones de rendimiento de eso, y si no necesita manejar los cambios de cuadro, entonces es solo un poco más complicado:
<ScrollView
onScroll={event => {
this.yOffset = event.nativeEvent.contentOffset.y
}}
scrollEventThrottle={16}
>
Para reducir la sobrecarga de rendimiento en iOS y, al mismo tiempo, garantizar que registremos cualquier posición en la que se asiente la vista de desplazamiento, podemos aumentar scrollEventThrottley, además, proporcionar un onScrollEndDragcontrolador:
<ScrollView
onScroll={event => {
this.yOffset = event.nativeEvent.contentOffset.y
}}
onScrollEndDrag={event => {
this.yOffset = event.nativeEvent.contentOffset.y
}}
scrollEventThrottle={160}
>
Pero si queremos manejar cambios de marco (por ejemplo, porque permitimos que se gire el dispositivo, cambiando la altura disponible para el marco de la vista de desplazamiento) y / o cambios de contenido, entonces debemos implementar adicionalmente tanto onContentSizeChangeyonLayout realizar un seguimiento de la altura de ambos el marco de la vista de desplazamiento y su contenido y, por lo tanto, calcular continuamente el desplazamiento máximo posible e inferir cuándo el desplazamiento se ha reducido automáticamente debido a un cambio de tamaño del marco o del contenido:
<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í, es bastante horrible. Tampoco estoy 100% seguro de que siempre funcione bien en los casos en los que cambie simultáneamente el tamaño del marco y el contenido de la vista de desplazamiento. Pero es lo mejor que se me ocurre, y hasta que esta característica se agregue dentro del marco en sí , creo que es lo mejor que cualquiera puede hacer.