Récupère la position de défilement actuelle de ScrollView dans React Native

Est-il possible d'obtenir la position de défilement actuelle, ou la page en cours de <ScrollView> composant Réagir Natif?

Donc quelque chose comme:

<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>
62
demandé sur Mark Amery 2015-04-08 02:35:01

8 réponses

Essayez.

<ScrollView onScroll={this.handleScroll} />

Puis:

handleScroll: function(event: Object) {
 console.log(event.nativeEvent.contentOffset.y);
},
129
répondu brad oyler 2015-04-08 13:07:39

Avertissement: ce qui suit est principalement le résultat de ma propre expérimentation dans React Native 0.50. Le ScrollView la documentation manque actuellement beaucoup des informations couvertes ci-dessous; par exemple onScrollEndDrag est complètement non documentée. Puisque tout ici repose sur un comportement non documenté, Je ne peux malheureusement pas promettre que cette information restera correcte dans un an ou même un mois.

En outre, tout ce qui suit suppose un scrollview purement vertical dont y offset nous intéresse; traduire enx offsets, si nécessaire, est un exercice facile pour le lecteur.


Divers gestionnaires d'événements sur un ScrollView prendre un event et vous permettent d'obtenir la position de défilement actuelle via event.nativeEvent.contentOffset.y. Certains de ces gestionnaires ont un comportement légèrement différent entre Android et iOS, comme détaillé ci-dessous.

onScroll

Sur Android

Déclenche chaque image pendant que l'utilisateur défile, sur chaque image pendant la vue de défilement glisse après que l'utilisateur la libère, sur l'image finale lorsque la vue de défilement se repose, et aussi chaque fois que le décalage de la vue de défilement change à la suite de son changement de cadre (par exemple en raison de la rotation du paysage au portrait).

Sur iOS

Se déclenche lorsque l'utilisateur fait glisser ou lorsque la vue de défilement glisse, à une fréquence déterminée par scrollEventThrottle et au plus une fois par image quand scrollEventThrottle={16}. Si l'utilisateur libère la vue de défilement pendant qu'elle a assez d'élan pour glisser, le gestionnaire onScroll se déclenchera également lorsqu'il s'agira de se reposer après le glissement. Cependant, si l'utilisateur fait glisser puis libère la vue de défilement alors qu'elle est stationnaire, onScroll n'est pas garanti pour la position finale à moins que scrollEventThrottle n'ait été défini de telle sorte que onScroll déclenche chaque image de défilement.

Il y a un coût de performance à définir {[11] } qui peut être réduit en le définissant sur un plus grand nombre. Cependant, cela signifie que onScroll ne déclenchera pas tous les cadre.

onMomentumScrollEnd

Se déclenche lorsque la vue de défilement s'arrête après le glissement. Ne se déclenche pas du tout si l'utilisateur libère la vue de défilement alors qu'elle est stationnaire de sorte qu'elle ne glisse pas.

onScrollEndDrag

Se déclenche lorsque l'utilisateur cesse de faire glisser la vue de défilement - que la vue de défilement reste immobile ou commence à glisser.


Compte tenu de ces différences de comportement, la meilleure façon de garder une trace du décalage dépend de votre circonstances précises. Dans le cas le plus compliqué (vous devez prendre en charge Android et iOS, y compris la gestion des changements dans le cadre de ScrollView en raison de la rotation, et vous ne voulez pas accepter la pénalité de performance sur Android de définir scrollEventThrottle à 16), et vous devez gérer les changements au contenu dans la vue de défilement aussi,

Le cas le plus simple est si vous avez seulement besoin de gérer Android; il suffit d'utiliser onScroll:

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

Pour prendre en charge iOS, si Vous êtes heureux de lancer le gestionnaire onScroll chaque image et d'accepter les implications de performance de cela, et si vous n'avez pas besoin de gérer les changements d'image, alors ce n'est qu'un peu plus compliqué:

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

Pour réduire la surcharge de performances sur iOS tout en garantissant que nous enregistrons n'importe quelle position sur laquelle la vue de défilement s'installe, nous pouvons augmenter scrollEventThrottle et fournir en outre un gestionnaire onScrollEndDrag:

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

Mais si nous voulons Gérer les changements de cadre (par exemple parce que nous autorisons la rotation du périphérique, en changeant la hauteur Disponible pour le cadre de la vue de défilement) et / ou les changements de contenu, nous devons en outre implémenter les deux onContentSizeChange et onLayout pour garder une trace de la hauteur du cadre de la vue de défilement et de son contenu, et ainsi calculer continuellement le décalage maximum possible et déduire lorsque le décalage a été automatiquement réduit en raison d'un changement de taille de cadre ou de contenu:

<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}
>

Ouais, c'est joli horribles. Je ne suis pas sûr à 100% que cela fonctionnera toujours correctement dans les cas où vous modifiez simultanément La Taille du cadre et du contenu de la vue de défilement. Mais c'est le meilleur que je puisse trouver, et jusqu'à ce que cette fonctionnalité soit ajoutée dans le cadre lui-même, je pense que c'est le meilleur que tout le monde puisse faire.

25
répondu Mark Amery 2018-04-13 08:35:38

La réponse de Brad Oyler est correcte. Mais vous ne recevrez qu'un seul événement. Si vous avez besoin d'obtenir des mises à jour constantes de la position de défilement, vous devez définir le scrollEventThrottle prop, comme ceci:

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

Et le gestionnaire d'événements:

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

Sachez que vous pourriez rencontrer des problèmes de performance. Ajustez la manette des gaz en conséquence. 16 Vous donne le plus de mises à jour. 0 un seul.

18
répondu cutemachine 2015-08-18 11:17:42

Si vous souhaitez simplement obtenir la position actuelle (par exemple lorsque vous appuyez sur un bouton) plutôt que de la suivre chaque fois que l'utilisateur défile, l'appel d'un écouteur onScroll entraînera des problèmes de performances. Actuellement, le moyen le plus performant d'obtenir simplement la position de défilement actuelle est d'utiliser le paquet react-native-invoke. Il y a un exemple pour cette chose exacte, mais le paquet fait plusieurs autres choses.

Lire à ce sujet ici. https://medium.com/@talkol/invoke-any-native-api-directly-from-pure-javascript-in-react-native-1fb6afcdf57d#.68ls1sopd

4
répondu Teodors 2017-12-26 22:24:37

Je crois que contentOffset vous donnera un objet contenant le décalage de défilement en haut à gauche:

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

2
répondu Colin Ramsay 2015-04-08 09:50:36

Cela devrait fonctionner pour Android et iOS (testé sur Android):

<ScrollView ref='myScrollView'>
  <Text>Blah</Text>
</ScrollView>

...

getOffset() {
  console.log(this.refs.myScrollView.scrollProperties.offset);
}
1
répondu Maiko Kuppe 2016-05-19 07:55:50

Pour obtenir le x / y après la fin du défilement comme les questions originales demandaient, le moyen le plus simple est probablement ceci:

<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
répondu j0n 2017-10-09 13:45:49

En ce qui concerne la page, je travaille sur un composant d'ordre supérieur qui utilise essentiellement les méthodes ci-dessus pour faire exactement cela. Il faut en fait juste un peu de temps quand vous descendez aux subtilités comme la mise en page initiale et les changements de contenu. Je ne prétendrai pas l'avoir fait "correctement", mais dans un certain sens, je considérerais la bonne réponse pour utiliser le composant qui le fait avec soin et cohérence.

Voir: réagir-native-paginé de défilement de la vue. J'adorerais les commentaires, même si c'est que je l'ai fait tout faux!

0
répondu 2015-12-08 16:14:32