Ist es möglich, eine ScrollView nach unten zu scrollen?

86

Für eine Chat-ähnliche App möchte ich eine ScrollViewKomponente nach unten scrollen lassen, da die neuesten Nachrichten unter den älteren angezeigt werden. Können wir die Bildlaufposition von a anpassen ScrollView?

Stirman
quelle
3
Ich weiß nichts über React-Native, aber denken Sie daran, dass Benutzer manchmal nach oben scrollen möchten, um den Chat-Verlauf anzuzeigen. Stellen Sie sicher, dass Sie den Chat nur scrollen, wenn der Chat bereits ganz nach unten gescrollt wurde, wenn eine neue Nachricht eintrifft.
David
Das ist eine gute Idee. Wir verfolgen dieses Problem hier: github.com/facebook/react-native/issues/107
Eric Vicenti
Ich habe gerade eine ähnliche Frage beantwortet, bitte überprüfen Sie sie hier - stackoverflow.com/a/32652967/1541508
Kohver
Beantwortet das deine Frage? So scrollen Sie zum Ende von React Native ListView
TripleM

Antworten:

161

Für React Native 0.41 und höher können Sie dies mit der integrierten scrollToEndMethode tun :

<ScrollView
    ref={ref => {this.scrollView = ref}}
    onContentSizeChange={() => this.scrollView.scrollToEnd({animated: true})}>
</ScrollView>
Aniruddha Shevle
quelle
3
Ab reaktionsnativ 0,55,4 und höher musste ich rootsonst verwenden, scrollToEnd ist undefiniert. dhthis.scrollView.root.scrollToEnd
Simon
4
Die Verwendung von react native 0.58.6 und using löst roottatsächlich einen undefinierten Fehler aus.
Jose Bernhardt
1
Sollte dies sein: ref={ref => {this.scrollView = ref}}da Sie die Aufgabe nicht zurückgeben möchten
Hampycalc
25

Verwenden Sie onContentSizeChange, um das untere Y der Bildlaufansicht (Höhe) zu verfolgen.

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

var _scrollToBottomY

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

Verwenden Sie dann den Referenznamen der Bildlaufansicht wie

this.refs.scrollView.scrollTo(_scrollToBottomY);
Drikoda
quelle
2
Beachten Sie, dass dadurch die Ansicht vollständig nach unten gescrollt wird, sodass die Ansicht im Wesentlichen nicht sichtbar ist (es sei denn, Sie haben nach der Messung etwas hinzugefügt). Dies ist sinnvoll, da der Code zur Höhe des scrollbaren Bereichs scrollt und nicht zur Höhe der Kinder, die den scrollbaren Bereich überlaufen (wahrscheinlich NICHT das, was OP wollte). Siehe stattdessen stackoverflow.com/a/39563193/1526986 .
Xixixao
20

Hier ist die einfachste Lösung, die ich aufbringen könnte:

 <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
    });
}}
/>;
Senornestor
quelle
1
Wenn ich diese oder ähnliche Antworten verwende, verschwinden die Elemente in der Liste (es sieht so aus, als würde es zu weit scrollen , aber ich kann nicht sicher sein). Wenn Sie ein kleines bisschen scrollen, wird alles wieder angezeigt, und es sieht so aus, als würde es wieder in Sichtweite geraten (daher das Scrollen zu weit). Irgendeine offensichtliche Idee, warum das sein könnte?
Tscizzle
9

Für alle, die Funktionskomponenten schreiben, die Hook verwenden können,

import React, { useRef } from 'react';
import { ScrollView } from 'react-native';

const ScreenComponent = (props) => {
  const scrollViewRef = useRef();
  return (
    <ScrollView
      ref={scrollViewRef}
      onContentSizeChange={() => scrollViewRef.current.scrollToEnd({ animated: true })}
    />
  );
};
Cltsang
quelle
5

Versuchen Sie diese Lösung

xcode 10.0

RN: 56.0.0

<ScrollView ref="scrollView"
             onContentSizeChange={(width,height) => this.refs.scrollView.scrollTo({y:height})}>  </ScrollView> // OR height -  width
Vishal Vaghasiya
quelle
warum ref=? scheint wie ein Web-
Entwickler-
4

Sie können die Bildlauf- / Listenansicht mithilfe des react-native-invertible-scroll-viewModuls umkehren und dann einfach aufrufen, ref.scrollTo(0)um nach unten zu scrollen.

Installieren Sie das Modul:

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

Importieren Sie dann die Komponente:

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

Verwenden Sie dann die folgende JSX anstelle von ScrollView:

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

Dies funktioniert, weil react-native-invertible-scroll-viewder gesamte Inhalt der Ansicht umgedreht wird. Beachten Sie, dass die untergeordneten Elemente der Ansicht auch in der entgegengesetzten Reihenfolge zu einer normalen Ansicht gerendert werden. Das erste untergeordnete Element wird unten angezeigt .

Irfaan
quelle
4

Für den Fall, dass sich jemand im Jahr 2020 oder später fragt, wie dies mit Funktionskomponenten erreicht werden kann. So habe ich es gemacht:

ref={ref => scrollView = ref }
onContentSizeChange={() => scrollView.scrollToEnd({ animated: true })}>
Marlon Englemam
quelle
Hinweis: Sie können erwähnen, dass Sie useref verwenden. Die meisten Leute wissen nicht, wie man Ref mit Hooks benutzt.
ɐɹƆzɐɹƆ
Ja. Die Sache ist, dass es auch dann funktioniert hat, wenn der useRef-Hook nicht verwendet wird. Aber der richtige Weg ist, es zu benutzen! Sie haben Recht
Marlon Englemam
2

Eigentlich hat die Antwort von @Aniruddha bei mir nicht funktioniert, weil ich sie benutze "react-native": "0.59.8"und this.scrollView.root.scrollToEndauch undefiniert bin

aber ich habe es herausgefunden und das funktioniert this.scrollView.scrollResponderScrollToEnd({animated: true});

Wenn Sie 0.59.8dies verwenden, funktioniert dies ODER wenn Sie eine spätere Version verwenden und dies für Sie funktioniert. Bitte fügen Sie Versionen in diese Antwort ein, damit andere keine Probleme bekommen.

Vollständiger Code hier

<ScrollView
    ref={ref => this.scrollView = ref}
    onContentSizeChange={(contentWidth, contentHeight)=>{        
        this.scrollView.scrollResponderScrollToEnd({animated: true});
    }}>
</ScrollView>
RajnishCoder
quelle
1

Diese Methode ist ein bisschen hacky, aber ich konnte keinen besseren Weg finden

  1. Fügen Sie Ihrer ScrollView zuerst eine Referenz hinzu.
  2. Fügen Sie anschließend eine Dummy-Ansicht hinzu, bevor Sie Ihr ScrollView-Tag schließen
  3. Ermitteln Sie die y-Position dieser Dummy-Ansicht
  4. Wenn Sie nach unten scrollen möchten, scrollen Sie zur Position der Dummy-Ansicht

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

Sritam
quelle
Dies ist nicht ganz das, wonach gefragt wurde; Dadurch wird beim Tippen nach unten gescrollt, anstatt die Bildlaufansicht beim Hinzufügen von Inhalten nach unten zu scrollen. Auf jeden Fall sind scrollToBottomsolche Ansätze in neueren Versionen von React Native überholt.
Mark Amery
1

Dies beantwortet Ihre Frage: https://stackoverflow.com/a/39563100/1917250

Sie müssen ständig zum Ende der Seite scrollen, indem Sie die Höhe des Inhalts abzüglich der Höhe der scrollView berechnen.

Saturnino
quelle
Dies ist die richtige Antwort auf die Frage. Sie können klug sein, wann Sie den Bildlauf ausführen sollen. Die Antwort im Link zeigt Ihnen, wie Sie die benötigten Zahlen erhalten. Insbesondere wenn Sie der Liste Komponenten hinzufügen, werden diese beim Aufrufen von componentDidUpdate in der Inhaltshöhe nicht berücksichtigt. Sie sollten sich also daran erinnern, dass Sie stattdessen auf onContentSizeChange scrollen und scrollen möchten.
Xixixao
1

Wenn Sie TypeScript verwenden, müssen Sie dies tun

interface Props extends TextInputProps { 
     scrollRef?: any;
}

export class Input extends React.Component<Props, any> {
     scrollRef;
constructor(props) {
    this.scrollRef = React.createRef();
}
<ScrollView
    ref={ref => (this.scrollRef = ref)}
    onContentSizeChange={() => {
    this.scrollRef.scrollToEnd();
    }}
>
</ScrollView>
Forhad
quelle
0

Ich habe eine Weile damit gekämpft und mir schließlich etwas ausgedacht, das für mich wirklich gut und reibungslos funktioniert hat. Wie viele habe ich erfolglos versucht .scrollToEnd. Die Lösung, die für mich funktionierte, war eine Kombination aus onContentSizeChange:onLayout Requisiten und ein bisschen mehr denken visuell über „was auf den Boden Scrollen“ wirklich bedeutete. Der letzte Teil scheint mir jetzt trivial, aber ich habe ewig gebraucht, um es herauszufinden.

Da das ScrollVieweine feste Höhe hat, berechnete ich den Versatz, wenn die Inhaltshöhe über die Höhe des Containers geht, indem ich die prevHeight(feste Höhe des ScrollView) für die currHeight(die Inhaltshöhe) subtrahiere . Wenn Sie es sich visuell vorstellen können, schieben Sie beim Scrollen zu diesem Unterschied in der y-Achse die Inhaltshöhe um diesen Versatz über den Container. Ich habe meinen Versatz erhöht und meine jetzt aktuelle Inhaltshöhe zu meiner vorherigen Höhe gemacht und einen neuen Versatz berechnet.

Hier ist der Code. Hoffe es hilft jemandem.

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>
    );
  }
}
Nelly Sugu
quelle
0

Ich denke, es ist zu spät, um zu antworten, aber ich habe einen Hack! Wenn Sie verwenden FlatListSie aktivieren invertedEigenschaft , die zur Einstellung fällt zurück transform scaleauf -1(die für andere Liste Komponenten wie akzeptabel ist ScrollView...). Wenn Sie Ihre FlatListDaten rendern, werden diese immer ganz unten angezeigt!

Abdumutal Abdusamatov
quelle
-1

Versuchen Sie, die contentOffset- Eigenschaft der Bildlaufansicht auf die aktuelle Höhe des Inhalts festzulegen .

Um das zu erreichen, was Sie benötigen, können Sie dies im Rahmen des onScroll-Ereignisses tun. Dies kann jedoch zu einer schlechten Benutzererfahrung führen, sodass es sich als benutzerfreundlicher erweisen kann, dies nur zu tun, wenn eine neue Nachricht angehängt wird.

Jack
quelle
-1; Nee. Wie viele der Antworten hier hat dies den Effekt, dass der gesamte Inhalt ScrollViewnach unten gescrollt wird, anstatt nur nach unten zu scrollen.
Mark Amery
-1

Ich hatte ein ähnliches Problem, aber nachdem ich diese Seite gelesen habe (was mir Kopfschmerzen bereitet !), Finde ich dieses sehr schöne npm-Paket, das einfach die ListView invertiert und alles für eine Chat-Anwendung einfach macht !!

Mehdi Sabouri
quelle
-1; Dies dupliziert eine zuvor veröffentlichte Antwort hier (und ist auch etwas verwirrt; diese Frage ScrollViewbezieht sich auf eine , nicht auf "ListView").
Mark Amery
-3

Ein bisschen spät ... aber sieh dir diese Frage an. Scrollen Sie zum Anfang von ScrollView

ScrollView verfügt über eine "scrollTo" -Methode.

George B.
quelle
1
Ja, es gibt eine scrollTo-Methode in ScrollView, aber die Frage bezieht sich speziell auf das Scrollen nach unten, was nicht einfach ist.
Southerneer