Est-il possible d'obtenir la position de défilement actuelle ou la page actuelle d'un composant <ScrollView>
dans React Native?
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>
Essayer.
<ScrollView onScroll={this.handleScroll} />
Et alors:
handleScroll: function(event: Object) {
console.log(event.nativeEvent.contentOffset.y);
},
Disclaimer: ce qui suit est principalement le résultat de ma propre expérience dans React Native 0.50. La documentation ScrollView
manque actuellement une grande partie des informations décrites ci-dessous; par exemple, onScrollEndDrag
est complètement non documenté. Étant donné que tout ici repose sur un comportement non documenté, je ne peux malheureusement rien promettre que ces informations resteront correctes dans un an, voire un mois.
En outre, tout ce qui suit est supposé être une vue de défilement purement verticale dont le décalage y nous intéresse; la traduction en x décalages, si nécessaire, est, espérons-le, un exercice facile pour le lecteur.
Différents gestionnaires d'événements sur une ScrollView
prennent une 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
Déclenche chaque image pendant le défilement de l'utilisateur, sur chaque image lorsque la vue défilante défile après le relâchement de l'utilisateur, sur la dernière image lorsque la vue défilante s'immobilise et également chaque fois que le décalage de la vue défilante résulte de son cadre. changeant (par exemple en raison de la rotation de paysage en portrait).
Se déclenche lorsque l'utilisateur fait glisser ou que la vue de défilement défile, à une fréquence déterminée par scrollEventThrottle
et au plus une fois par image lorsque scrollEventThrottle={16}
. Si l'utilisateur relâche la vue de défilement alors qu'il a suffisamment de temps pour glisser, le gestionnaire onScroll
sera également déclenché lorsqu'il s'arrêtera après avoir plané. Cependant, si l'utilisateur fait glisser puis relâche la vue de défilement alors qu'elle est immobile, la variable onScroll
est non garantie pour la position finale, à moins que scrollEventThrottle
ne soit défini de telle sorte que onScroll
déclenche chaque image du défilement.
La définition de scrollEventThrottle={16}
entraîne des coûts de performance que vous pouvez réduire en définissant un nombre plus élevé. Cependant, cela signifie que onScroll
ne déclenchera pas toutes les images.
onMomentumScrollEnd
Se déclenche lorsque la vue de défilement s’arrête après le vol plané. Ne se déclenche pas du tout si l'utilisateur relâche la vue de défilement alors qu'elle est immobile, de sorte qu'elle ne glisse pas.
onScrollEndDrag
Se déclenche lorsque l'utilisateur arrête de faire glisser la vue de défilement, que la vue de défilement reste immobile ou qu'elle commence à glisser.
Compte tenu de ces différences de comportement, le meilleur moyen de suivre le décalage dépend de votre situation précise. Dans le cas le plus compliqué (vous devez prendre en charge Android et iOS, y compris la gestion des modifications du cadre de la ScrollView
dues à la rotation, et vous ne voulez pas accepter la pénalité de performance sous Android du paramètre scrollEventThrottle
à 16), et vous devez gérer modifie le contenu dans la vue de défilement aussi, alors c'est un foutu bordel.
Le cas le plus simple est si vous avez seulement besoin de gérer Android; utilisez simplement onScroll
:
<ScrollView
onScroll={event => {
this.yOffset = event.nativeEvent.contentOffset.y
}}
>
Pour prendre également en charge iOS, si vous êtes prêt à déclencher le gestionnaire onScroll
à chaque image et à en assumer les conséquences sur les performances, et si vous n'avez pas besoin de gérer les modifications d'image, c'est seulement un petit 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 toute position sur laquelle la vue de défilement se règle, 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 modifications de cadre (par exemple, parce que nous autorisons la rotation de l'appareil et la modification de la hauteur disponible pour le cadre de la vue de défilement) et/ou les modifications de contenu, nous devons également implémenter à la fois 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 en permanence le décalage possible maximum et en déduire lorsque le décalage a été automatiquement réduit en raison d'un changement de taille du cadre ou du 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 assez horrible. Je ne suis pas certain à 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 même , je pense que c'est le meilleur que tout le monde puisse faire.
La réponse de Brad Oyler est correcte. Mais vous ne recevrez qu'un seul événement. Si vous devez obtenir des mises à jour constantes de la position du défilement, vous devez définir la propriété scrollEventThrottle
, comme suit:
<ScrollView onScroll={this.handleScroll} scrollEventThrottle={16} >
<Text>
Be like water my friend …
</Text>
</ScrollView>
Et le gestionnaire d'événement:
handleScroll: function(event: Object) {
console.log(event.nativeEvent.contentOffset.y);
},
Sachez que vous pouvez rencontrer des problèmes de performances. Ajustez l'accélérateur en conséquence. 16 vous donne le plus de mises à jour. 0 un seul.
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 fait défiler, invoquer un écouteur onScroll
entraînera des problèmes de performances. Actuellement, la méthode la plus performante pour obtenir simplement la position de défilement actuelle consiste à utiliser react-native-invoke package. Il existe un exemple pour cette chose exacte, mais le paquet fait plusieurs autres choses.
Lisez à ce sujet ici . https://medium.com/@talkol/invoke-any-native-api-directly-from-pure-javascript-in-react-native-1fb6afcdf57d#.68ls1sopd
Pour obtenir le x/y après la fin du défilement comme le demandaient les questions initiales, le plus simple est probablement le suivant:
<ScrollView
horizontal={true}
pagingEnabled={true}
onMomentumScrollEnd={(event) => {
// scroll animation ended
console.log(e.nativeEvent.contentOffset.x);
console.log(e.nativeEvent.contentOffset.y);
}}>
...content
</ScrollView>
En ce qui concerne la page, je travaille sur un composant d'ordre supérieur qui utilise fondamentalement les méthodes ci-dessus pour faire exactement cela. En fait, cela prend un peu de temps lorsque vous abordez les subtilités telles que la modification de la présentation initiale et du contenu. Je ne prétends pas l'avoir "fait" correctement, mais dans un certain sens, je considérerais la bonne réponse pour utiliser un composant qui le fait avec soin et cohérence.
Voir: react-native-paged-scroll-view . J'adorerais les commentaires, même si c'est parce que j'ai tout faux!
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
Voici comment vous avez fini par obtenir la position de défilement actuelle en direct de la vue. Tout ce que je fais est d'utiliser l'écouteur d'événements sur le défilement et le scrollEventThrottle. Je le passe alors comme un événement pour gérer la fonction de défilement que j'ai créée et mettre à jour mes accessoires.
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} />
)
}
}