web-dev-qa-db-fra.com

React Native - comment faire défiler un ScrollView vers un emplacement donné après la navigation à partir d'un autre écran

Est-il possible de dire à un ScrollView de faire défiler jusqu'à une position spécifique lorsque nous venons de naviguer vers l'écran actuel via StackNavigator?

J'ai deux écrans; Menu et éléments. Le menu est une liste de boutons, un pour chaque élément. L'écran Articles contient un carrousel construit à l'aide de ScrollView avec l'image et la description détaillée de chaque article.

Lorsque je clique sur un bouton de l'écran Menu, je souhaite accéder à l'écran Éléments et faire défiler automatiquement jusqu'à l'élément que le bouton représente.

J'ai lu que vous pouvez passer des paramètres lorsque vous utilisez StackNavigator comme ceci: mais je ne sais pas comment lire ce paramètre dans mon écran Articles.

navigate('Items', { id: '1' })

Est-ce donc quelque chose qui est possible en React Native et comment dois-je le faire? Ou peut-être que j'utilise le mauvais navigateur?

Voici une version abrutie de mes deux écrans:

App.js:

const SimpleApp = StackNavigator({
    Menu: { screen: MenuScreen},
    Items: { screen: ItemScreen }
  }
);

export default class App extends React.Component {
  render() {
    return <SimpleApp />;
  }
}

Menu.js

export default class Menu extends React.Component {
    constructor(props){
        super(props)
        this.seeDetail = this.seeDetail.bind(this)
    }

    seeDetail(){
        const { navigate } = this.props.navigation;
        navigate('Items')
    }

    render(){
        <Button onPress={this.seeDetail} title='1'/>
        <Button onPress={this.seeDetail} title='2'/>
    }
}

Items.js

export default class Items extends React.Component {
  render(){
    let scrollItems = [] //Somecode that generates and array of items
    return (
      <View>
        <View style={styles.scrollViewContainer}>
          <ScrollView 
          horizontal
          pagingEnabled
          ref={(ref) => this.myScroll = ref}>
            {scrollItems}
          </ScrollView>
        </View>
      </View>
    )
  }  
}

P.S Je cible spécifiquement Android pour le moment, mais idéalement, il pourrait y avoir une solution multiplateforme.

8
davidx1

J'ai lu que vous pouvez passer des paramètres lorsque vous utilisez StackNavigator comme ceci: mais je ne sais pas comment lire ce paramètre dans mon écran Articles.

Pour ce faire, accédez à this.props.navigation.state.params à l'intérieur de votre composant enfant.

Je pense que le meilleur moment pour appeler scrollTo sur votre référence scrollview est la première fois qu'elle est affectée. Vous lui donnez déjà une référence et exécutez une fonction de rappel - je voudrais juste la modifier pour qu'il appelle également scrollTo en même temps:

export default class Items extends React.Component {
  render(){
    let scrollItems = [] //Somecode that generates and array of items
    const {id} = this.props.navigation.state.params;

    return (
      <View>
        <View style={styles.scrollViewContainer}>
          <ScrollView 
          horizontal
          pagingEnabled
          ref={(ref) => {
            this.myScroll = ref
            this.myScroll.scrollTo() // !!
          }>
            {scrollItems}
          </ScrollView>
        </View>
      </View>
    )
  }  
}

Et c'est pourquoi j'utilise FlatLists ou SectionLists (qui héritent de VirtualizedList ) au lieu de ScrollViews. VirtualizedList a une fonction scrollToIndex qui est beaucoup plus intuitive. ScrollView's scrollTo attend les paramètres x et y, ce qui signifie que vous devrez calculer l'endroit exact pour faire défiler - en multipliant la largeur de chaque élément de défilement par l'index de l'élément vers lequel vous faites défiler. Et s'il y a un rembourrage impliqué pour chaque article, cela devient plus une douleur.

6
Pat Needham

Voici un exemple de défilement vers les accessoires avec id.

import React, { Component } from 'react';
import { StyleSheet, Text, View, ScrollView, TouchableOpacity, Dimensions, Alert, findNodeHandle, Image } from 'react-native';
class MyCustomScrollToElement extends Component {

constructor(props) {
  super(props)
  this.state = {
  }
  this._nodes = new Map();
}
componentDidMount() {
  const data = ['First Element', 'Second Element', 'Third Element', 'Fourth Element', 'Fifth Element' ];
  data.filter((el, idx) => {
    if(el===this.props.id){
      this.scrollToElement(idx);
    }
  })

}
scrollToElement =(indexOf)=>{
  const node = this._nodes.get(indexOf);
  const position = findNodeHandle(node);
  this.myScroll.scrollTo({ x: 0, y: position, animated: true });
}
render(){
  const data = ['First Element', 'Second Element', 'Third Element', 'Fourth Element', 'Fifth Element' ];
  return (
  <View style={styles.container}>
    <ScrollView ref={(ref) => this.myScroll = ref} style={[styles.container, {flex:0.9}]} keyboardShouldPersistTaps={'handled'}>
      <View style={styles.container}>
          {data.map((Elm, idx) => <View ref={ref => this._nodes.set(idx, ref)} style={{styles.element}}><Text>{Elm}</Text></View>)}
      </View>
    </ScrollView>
  </View>
);

}

const styles = StyleSheet.create({
container: {
  flexGrow: 1,
  backgroundColor:"#d7eff9"
},
element:{
  width: 200,
  height: 200,
  backgroundColor: 'red'
}
});
export default MyCustomScrollToElement;

Oui, cela est possible en utilisant la méthode scrollTo - voir docs . Vous pouvez appeler cette méthode dans componentDidMount. Vous avez juste besoin d'une référence pour l'appeler comme: this.myScroll.scrollTo(...). Notez que si vous disposez d'un tableau d'éléments qui sont tous du même type, vous devez utiliser FlatList à la place.

1
vonovak

Pour iOS - la meilleure façon d'utiliser la propriété ScrollView de contentOffset. De cette façon, il sera initialement rendu dans la bonne position. L'utilisation de scrollTo ajoutera un rendu supplémentaire supplémentaire après le premier.

Pour Android - il n'y a pas d'autre option que scrollTo

0
Nick Avasiloy