web-dev-qa-db-fra.com

Est-il possible de faire défiler une ScrollView vers le bas?

Pour une application de type chat, je souhaite faire défiler un composant ScrollView vers le bas, car les messages les plus récents apparaissent sous les anciens. Pouvons-nous ajuster la position de défilement d'une ScrollView?

63
Stirman

Pour React Native 0.41 et versions ultérieures, vous pouvez le faire avec la méthode scrollToEnd intégrée:

<ScrollView
    ref={ref => this.scrollView = ref}
    onContentSizeChange={(contentWidth, contentHeight)=>{        
        this.scrollView.scrollToEnd({animated: true});
    }}>
</ScrollView>
94
Aniruddha Shevle

Utilisez onContentSizeChange pour garder une trace du Y inférieur de la vue de défilement (hauteur)

https://facebook.github.io/react-native/docs/scrollview.html#oncontentsizechange

var _scrollToBottomY

<ScrollView
    onContentSizeChange={(contentWidth, contentHeight)=>{
    _scrollToBottomY = contentHeight;
    }}>
</ScrollView>

puis utilisez le nom de référence de la vue de défilement comme 

this.refs.scrollView.scrollTo(_scrollToBottomY);
24
drikoda

Voici la solution la plus simple que je pourrais trouver:

 <ListView
ref={ref => (this.listView = ref)}
onLayout={event => {
    this.listViewHeight = event.nativeEvent.layout.height;
}}
onContentSizeChange={() => {
    this.listView.scrollTo({
        y: this.listView.getMetrics().contentLength - this.listViewHeight
    });
}}
/>;
18
senornestor

Vous pouvez inverser la vue de défilement/liste à l’aide du module react-native-invertible-scroll-view , puis appelez simplement ref.scrollTo(0) pour faire défiler vers le bas.

Installez le module:

npm install --save react-native-invertible-scroll-view

Importez ensuite le composant:

import InvertibleScrollView from 'react-native-invertible-scroll-view';

Ensuite, utilisez le fichier JSX suivant au lieu de ScrollView:

<InvertibleScrollView inverted
    ref={ref => { this.scrollView = ref; }}
    onContentSizeChange={() => {
        this.scrollView.scrollTo({y: 0, animated: true});
    }}
>
    { /* content */ }
</InvertibleScrollView>

Cela fonctionne parce que react-native-invertible-scroll-view retourne le contenu de la vue entière. Notez que les enfants de la vue seront également rendus dans l'ordre inverse de la vue normale - le premier enfant apparaîtra au bottom.

2
irfaan

Cette méthode est un peu compliquée mais je ne pouvais pas trouver un meilleur moyen

  1. Ajoutez d’abord une référence à votre ScrollView.
  2. Deuxièmement, ajoutez une vue factice avant de fermer votre balise ScrollView
  3. Obtenir la position y de ce mannequin Voir
  4. Chaque fois que vous souhaitez faire défiler vers le bas, faites défiler jusqu'à la position du dummy View

var footerY; //Y position of the dummy view
render() {    
    return (
      <View>
          <ScrollView 
          ref='_scrollView'>
            // This is where all the things that you want to display in the scroll view goes
            
            // Below is the dummy View
            <View onLayout={(e)=> {
              footerY = e.nativeEvent.layout.y;
              }}/>
          </ScrollView>
              
          //Below is the button to scroll to the bottom    
          <TouchableHighlight
            onPress={() => { this.refs._scrollView.scrollTo(footerY); }}>
            <Text>Scroll to Bottom</Text>
          </TouchableHighlight>
        
      </View>
    );
  }

1
Sritam

essayez cette solution

xcode 10.0

RN: 56.0.0

<ScrollView ref="scrollView"
             onContentSizeChange={(width,height) => this.refs.scrollView.scrollTo({y:height})}>  </ScrollView> // OR height -  width
1
Vishal Vaghasiya

Cela aidera peut-être quelqu'un qui a des problèmes similaires à gérer des éléments d'une liste.

Cela fera défiler jusqu'au dernier élément de la liste. Je l'utilise dans une application de messagerie.

<FlatList
    data={data.messages}
    ref={ref => this.scrollView = ref}
    onContentSizeChange={(contentWidth, contentHeight)=>{
        this.scrollView.scrollToIndex({index: data.messages.length - 2});
    }}
    renderItem={({item}) => this.renderItem(item)}
/>
0
spedy

Je me suis battu avec ça pendant un moment et finalement j'ai trouvé quelque chose qui a vraiment bien fonctionné et qui s'est bien déroulé pour moi. Comme beaucoup, j'ai essayé .scrollToEnd sans succès. La solution qui a fonctionné pour moi était une combinaison d'accessoires onContentSizeChange, onLayout et un peu plus réfléchissant visuellement à «ce que faire défiler vers le bas» signifiait vraiment. La dernière partie me semble banale maintenant, mais il me fallut une éternité pour comprendre. 

Étant donné que la ScrollView a une hauteur fixe, lorsque la hauteur du contenu dépasse celle du conteneur, j'ai calculé le décalage en soustrayant la prevHeight (hauteur fixe de la ScrollView) pour la currHeight (hauteur du contenu). Si vous pouvez l'imaginer visuellement, en faisant défiler la différence d'axe des y jusqu'à la différence, faites glisser la hauteur du contenu sur son conteneur de ce décalage. J'ai incrémenté mon décalage et transformé le contenu actuel en hauteur en hauteur précédente tout en calculant un nouveau décalage.

Voici le code. J'espère que ça aide quelqu'un.

class ChatRoomCorrespondence extends PureComponent {
  currHeight = 0;
  prevHeight = 0;
  scrollHeight = 0;

  scrollToBottom = () => {
    this.refs.scrollView.getScrollResponder().scrollResponderScrollTo({
      x: 0,
      y: this.scrollHeight,
      animated: true
    });
  };

  render() {
    return (
      <ScrollView
        style={Styles.container}
        ref="scrollView"
        onContentSizeChange={(w, h) => {
          this.currHeight = h;

          if (
            this.prevHeight > 0 &&
            this.currHeight - this.scrollHeight > this.prevHeight
          ) {
            this.scrollHeight += this.currHeight - this.prevHeight;
            console.log("--------------------------------------------");
            console.log("Curr: ", this.currHeight);
            console.log("Prev: ", this.prevHeight);
            console.log("Scroll: ", this.scrollHeight);
            this.prevHeight = this.currHeight;
            console.log("PREV: ", this.prevHeight);
            console.log("--------------------------------------------");

            this.scrollToBottom();
          }
        }}
        onLayout={ev => {
          // Fires once
          const fixedContentHeight = ev.nativeEvent.layout.height;
          this.prevHeight = fixedContentHeight;
        }}
      >
        <FlatList
          data={this.props.messages}
          renderItem={({ item }) => (
            <ChatMessage
              text={item.text}
              sender={item.sender}
              time={item.time}
              username={this.props.username}
            />
          )}
          keyExtractor={(item, index) => index.toString()}
        />
      </ScrollView>
    );
  }
}
0

J'imagine qu'il est trop tard pour répondre, mais j'en ai un! Si vous utilisez FlatList, vous pouvez activer la propriété inverted qui revient à définir transform scale sur -1 (acceptable pour d'autres composants de liste tels que ScrollView ... ). Lorsque vous restituez votre FlatList avec des données, il sera toujours en bas!

0

Cela répond à votre question: https://stackoverflow.com/a/39563100/1917250

Vous devez constamment faire défiler la page jusqu'en bas en calculant la hauteur du contenu moins la hauteur de son scrollView.

0
Saturnino