Haftungsausschluss: Was folgt, ist in erster Linie das Ergebnis meiner eigenen Experimente in React Native 0.50. In der ScrollView
Dokumentation fehlen derzeit viele der unten behandelten Informationen. zum BeispielonScrollEndDrag
ist völlig undokumentiert. Da hier alles auf undokumentiertem Verhalten beruht, kann ich leider nicht versprechen, dass diese Informationen in einem Jahr oder sogar einem Monat korrekt bleiben.
Außerdem setzt alles unten eine rein vertikale Bildlaufansicht voraus, deren y- Versatz uns interessiert; Das Übersetzen in x Offsets, falls erforderlich, ist hoffentlich eine einfache Übung für den Leser.
Verschiedene Event-Handler ScrollView
nehmen eine Aufnahme event
und lassen Sie die aktuelle Bildlaufposition über abrufen event.nativeEvent.contentOffset.y
. Einige dieser Handler haben ein etwas anderes Verhalten zwischen Android und iOS, wie unten beschrieben.
Auf Android
Löst jedes Bild aus, während der Benutzer einen Bildlauf durchführt, auf jedem Bild, während die Bildlaufansicht nach dem Loslassen durch den Benutzer gleitet, auf dem letzten Bild, wenn die Bildlaufansicht zum Stillstand kommt, und auch dann, wenn sich der Versatz der Bildlaufansicht aufgrund des Bilds ändert Ändern (z. B. durch Drehung von Querformat zu Hochformat).
Unter iOS
Wird ausgelöst, während der Benutzer zieht oder während die Bildlaufansicht gleitet, mit einer Häufigkeit, die von scrollEventThrottle
und höchstens einmal pro Bild bestimmt wird, wenn scrollEventThrottle={16}
. Wenn der Benutzer die Bildlaufansicht freigibt, während er genügend Schwung zum Gleiten hat, wird der onScroll
Handler auch ausgelöst, wenn er nach dem Gleiten zur Ruhe kommt. Wenn der Benutzer die Bildlaufansicht jedoch zieht und dann im Stillstand freigibt, onScroll
ist dies nicht der Fall garantiert, dass sie für die endgültige Position ausgelöst scrollEventThrottle
wird, es sei denn, sie wurde so eingestellt, dass onScroll
jedes Bildlaufbild ausgelöst wird.
Das Einstellen verursacht Leistungskosten, die scrollEventThrottle={16}
durch Einstellen auf eine größere Anzahl reduziert werden können. Dies bedeutet jedoch, dass onScroll
nicht jeder Frame ausgelöst wird.
Wird ausgelöst, wenn die Bildlaufansicht nach dem Gleiten zum Stillstand kommt. Wird überhaupt nicht ausgelöst, wenn der Benutzer die Bildlaufansicht im Stillstand so freigibt, dass sie nicht gleitet.
onScrollEndDrag
Wird ausgelöst, wenn der Benutzer das Ziehen der Bildlaufansicht beendet - unabhängig davon, ob die Bildlaufansicht stationär bleibt oder zu gleiten beginnt.
Angesichts dieser Verhaltensunterschiede hängt der beste Weg, den Versatz zu verfolgen, von Ihren genauen Umständen ab. Im kompliziertesten Fall (Sie müssen Android und iOS unterstützen, einschließlich der Behandlung von Änderungen im ScrollView
Rahmen aufgrund von Rotation, und Sie möchten die Leistungseinbußen bei Android von Einstellung scrollEventThrottle
auf 16 nicht akzeptieren ), und Sie müssen damit umgehen ändert sich auch der Inhalt in der Bildlaufansicht, dann ist es ein verdammtes Durcheinander.
Der einfachste Fall ist, wenn Sie nur mit Android umgehen müssen. benutze einfach onScroll
:
<ScrollView
onScroll={event => {
this.yOffset = event.nativeEvent.contentOffset.y
}}
>
Um iOS zusätzlich zu unterstützen , ist es nur ein bisschen komplizierter , wenn Sie den onScroll
Handler gerne in jedem Frame auslösen und die Auswirkungen auf die Leistung akzeptieren und wenn Sie keine Frame-Änderungen vornehmen müssen:
<ScrollView
onScroll={event => {
this.yOffset = event.nativeEvent.contentOffset.y
}}
scrollEventThrottle={16}
>
Um den Leistungsaufwand unter iOS zu verringern und gleichzeitig sicherzustellen, dass alle Positionen aufgezeichnet werden, an denen sich die Bildlaufansicht befindet, können wir scrollEventThrottle
den onScrollEndDrag
Handler erhöhen und zusätzlich bereitstellen :
<ScrollView
onScroll={event => {
this.yOffset = event.nativeEvent.contentOffset.y
}}
onScrollEndDrag={event => {
this.yOffset = event.nativeEvent.contentOffset.y
}}
scrollEventThrottle={160}
>
Wenn wir jedoch Rahmenänderungen (z. B. weil wir das Gerät drehen lassen, die verfügbare Höhe für den Rahmen der Bildlaufansicht ändern) und / oder Inhaltsänderungen verarbeiten möchten, müssen wir beide zusätzlich implementieren onContentSizeChange
und onLayout
die Höhe beider verfolgen den Rahmen und den Inhalt der Bildlaufansicht und berechnen dabei kontinuierlich das Maximum möglichen Versatz und schließen daraus, wenn der Versatz aufgrund einer Änderung der Rahmen- oder Inhaltsgröße automatisch verringert wurde:
<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}
>
Ja, es ist ziemlich schrecklich. Ich bin mir auch nicht 100% sicher, dass es immer richtig funktioniert, wenn Sie gleichzeitig die Größe des Rahmens und den Inhalt der Bildlaufansicht ändern. Aber es ist das Beste, was ich mir vorstellen kann, und bis diese Funktion innerhalb des Frameworks selbst hinzugefügt wird , denke ich, dass dies das Beste ist, was jeder tun kann.