wake-up-neo.net

Aktuelle Bildlaufposition von ScrollView in React Native anzeigen

Kann die aktuelle Bildlaufposition oder die aktuelle Seite einer <ScrollView>-Komponente in React Native abgerufen werden?

So etwas wie:

<ScrollView
  horizontal={true}
  pagingEnabled={true}
  onScrollAnimationEnd={() => { 
      // get this scrollview's current page or x/y scroll position
  }}>
  this.state.data.map(function(e, i) { 
      <ImageCt key={i}></ImageCt> 
  })
</ScrollView>
73
Sang

Versuchen.

<ScrollView onScroll={this.handleScroll} />

Und dann: 

handleScroll: function(event: Object) {
 console.log(event.nativeEvent.contentOffset.y);
},
144
brad oyler

Haftungsausschluss: Das Folgende ist in erster Linie das Ergebnis meiner eigenen Experimente in React Native 0.50. In der ScrollView Dokumentation fehlen derzeit viele der behandelten Informationen Beispiel: onScrollEndDrag ist vollständig undokumentiert. Da hier alles von undokumentiertem Verhalten abhängt, kann ich leider keine Zusicherung machen, dass diese Informationen in einem Jahr oder sogar in einem Monat korrekt bleiben.

Außerdem setzt alles unten eine rein vertikale Scrollansicht voraus, deren y Offset uns interessiert; Das Übersetzen in x Offsets, falls erforderlich, ist hoffentlich eine leichte Übung für den Leser.


Verschiedene Event-Handler auf einem ScrollView nehmen ein event und lassen Sie die aktuelle Bildlaufposition über event.nativeEvent.contentOffset.y Abrufen. Einige dieser Handler haben ein leicht unterschiedliches Verhalten zwischen Android und iOS, wie unten beschrieben.

onScroll

Auf Android

Feuert jedes Bild, während der Benutzer einen Bildlauf ausführt, auf jedem Bild, während die Bildlaufansicht nach dem Loslassen gleitet, auf dem letzten Bild, wenn die Bildlaufansicht zum Stillstand kommt, und auch dann, wenn sich der Versatz der Bildlaufansicht aufgrund des Bildlaufs ändert Ändern (zB durch Rotation von Querformat zu Hochformat).

Auf iOS

Wird ausgelöst, während der Benutzer zieht oder während die Bildlaufansicht gleitet, mit einer Häufigkeit, die durch scrollEventThrottle und höchstens einmal pro Frame bei scrollEventThrottle={16} Bestimmt wird. If Der Benutzer gibt die Bildlaufansicht frei, während er genug Schwung zum Gleiten hat. Der onScroll -Handler wird auch ausgelöst, wenn er nach dem Gleiten zur Ruhe kommt. Wenn der Benutzer jedoch die Bildlaufansicht zieht und dann loslässt, während sie stationär ist, wird onScroll not garantiert für die Endposition ausgelöst, es sei denn, scrollEventThrottle wurde ausgelöst Stellen Sie dies so ein, dass onScroll jeden Bildlauf auslöst.

Die Einstellung von scrollEventThrottle={16} Ist mit einem Leistungsaufwand verbunden, der durch eine höhere Anzahl verringert werden kann. Dies bedeutet jedoch, dass onScroll nicht jeden Frame auslöst.

onMomentumScrollEnd

Wird ausgelöst, wenn die Bildlaufansicht nach dem Gleiten angehalten wird. Wird überhaupt nicht ausgelöst, wenn der Benutzer die Bildlaufansicht loslässt, während sie stillsteht, sodass sie nicht gleitet.

onScrollEndDrag

Wird ausgelöst, wenn der Benutzer aufhört, die Bildlaufansicht zu ziehen - unabhängig davon, ob die Bildlaufansicht stationär bleibt oder zu gleiten beginnt.


Angesichts dieser Verhaltensunterschiede hängt der beste Weg, den Offset 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 Rahmen von ScrollView aufgrund von Rotation, und Sie möchten die Leistungseinbußen nicht akzeptieren Wenn Sie Android von scrollEventThrottle auf 16 setzen), und Sie Änderungen an content auch in der Bildlaufansicht vornehmen müssen, ist es ein verdammt noch mal.

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 zusätzlich iOS zu unterstützen, wenn können Sie den onScroll -Handler gerne für jeden Frame auslösen und die Auswirkungen auf die Leistung akzeptieren, und wenn Sie müssen nicht mit Frame-Änderungen umgehen, dann ist es nur ein bisschen komplizierter:

<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, auf denen sich die Bildlaufansicht befindet, können wir scrollEventThrottle erhöhen und zusätzlich einen onScrollEndDrag -Handler bereitstellen:

<ScrollView
  onScroll={event => { 
    this.yOffset = event.nativeEvent.contentOffset.y
  }}
  onScrollEndDrag={event => { 
    this.yOffset = event.nativeEvent.contentOffset.y
  }}
  scrollEventThrottle={160}
>

Wenn wir jedoch Änderungen an Frames vornehmen möchten (z. B. weil wir das Drehen des Geräts zulassen und die verfügbare Höhe für den Frame der Bildlaufansicht ändern) und/oder Änderungen an Inhalten vornehmen möchten, müssen wir zusätzlich beide implementieren: onContentSizeChange und onLayout , um die Höhe sowohl des Rahmens als auch des Inhalts der Bildlaufansicht zu verfolgen und dabei kontinuierlich das mögliche Maximum zu berechnen Versatz und Rückschluss, 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 sowohl des Rahmens als auch des Inhalts der Bildlaufansicht ändern. Aber es ist das Beste, was ich mir einfallen lassen kann, und bis diese Funktion wird innerhalb des Frameworks selbst hinzugefügt denke ich, ist dies das Beste, was jeder tun kann.

42
Mark Amery

Die Antwort von Brad Oyler ist richtig. Sie erhalten jedoch nur eine Veranstaltung. Wenn Sie ständige Aktualisierungen der Bildlaufposition benötigen, sollten Sie die scrollEventThrottle -Eigenschaft wie folgt einstellen:

<ScrollView onScroll={this.handleScroll} scrollEventThrottle={16} >
  <Text>
    Be like water my friend …
  </Text>
</ScrollView>

Und der Eventhandler:

handleScroll: function(event: Object) {
  console.log(event.nativeEvent.contentOffset.y);
},

Beachten Sie, dass möglicherweise Leistungsprobleme auftreten. Stellen Sie die Drossel entsprechend ein. 16 gibt Ihnen die meisten Updates. 0 nur eine.

18
cutemachine

Wenn Sie einfach die aktuelle Position abrufen möchten (z. B., wenn eine Schaltfläche gedrückt wird), anstatt sie bei jedem Bildlauf des Benutzers zu verfolgen, führt das Aufrufen eines onScroll-Listeners zu Leistungsproblemen. Derzeit ist der beste Weg, die aktuelle Bildlaufposition einfach abzurufen, die Verwendung von reag-native-invoke package. Es gibt ein Beispiel für diese genaue Sache, aber das Paket führt mehrere andere Dinge aus.

Lesen Sie dazu hier . https://medium.com/@talkol/invoke-any-native-api-directly-from-pure-javascript-in-react-native-1fb6afcdf57d#.68ls1sopd

6
Teodors

Um das x/y nach dem Scrollen zu beenden, wenn die ursprünglichen Fragen angefragt wurden, ist der wahrscheinlichste Weg der folgende:

<ScrollView
   horizontal={true}
   pagingEnabled={true}
   onMomentumScrollEnd={(event) => { 
      // scroll animation ended
      console.log(e.nativeEvent.contentOffset.x);
      console.log(e.nativeEvent.contentOffset.y);
   }}>
   ...content
</ScrollView>
1
j0n

Was die Seite angeht, arbeite ich an einer Komponente höherer Ordnung, die im Wesentlichen die oben genannten Methoden verwendet, um genau dies zu tun. Es dauert tatsächlich nur ein wenig Zeit, wenn Sie zu den Feinheiten wie dem ursprünglichen Layout und den Inhaltsänderungen gelangen. Ich behaupte nicht, es "richtig" gemacht zu haben, aber in gewissem Sinne würde ich die richtige Antwort für die Verwendung einer Komponente betrachten, die dies sorgfältig und konsequent durchführt.

Siehe: Reagieren-native-paged-scroll-view . Würde mich über Feedback freuen, auch wenn ich es falsch gemacht habe!

0
user657199

Ich glaube, dass contentOffset Ihnen ein Objekt geben wird, das den oberen linken Bildlaufversatz enthält:

http://facebook.github.io/react-native/docs/scrollview.html#contentoffset

0
Colin Ramsay

Auf diese Weise wurde die aktuelle Bildlaufposition von der Ansicht aus live angezeigt. Alles was ich mache, ist der on scroll Ereignislistener und die scrollEventThrottle. Ich übergebe es dann als Ereignis, um die von mir erstellte Bildlauffunktion und das Aktualisieren meiner Requisiten durchzuführen. 

 export default class Anim extends React.Component {
          constructor(props) {
             super(props);
             this.state = {
               yPos: 0,
             };
           }

        handleScroll(event){
            this.setState({
              yPos : event.nativeEvent.contentOffset.y,
            })
        }

        render() {
            return (
          <ScrollView onScroll={this.handleScroll.bind(this)} scrollEventThrottle={16} />
    )
    }
    }
0
Sabba Keynejad