121

对于类似聊天的应用程序,我想让一个ScrollView组件滚动到底部,因为最新消息显示在旧消息下方。我们可以调整 a 的滚动位置ScrollView吗?

4

16 回答 16

203

对于React Native 0.41 及更高版本,您可以使用内置scrollToEnd方法执行此操作:

<ScrollView
    ref={ref => {this.scrollView = ref}}
    onContentSizeChange={() => this.scrollView.scrollToEnd({animated: true})}>
</ScrollView>
于 2017-03-11T14:02:25.900 回答
66

对于任何编写可以使用钩子的函数组件的人,

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 })}
    />
  );
};
于 2020-06-04T06:23:59.780 回答
29

使用 onContentSizeChange 跟踪滚动视图的底部 Y(高度)

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

var _scrollToBottomY

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

然后使用滚动视图的引用名称,如

this.refs.scrollView.scrollTo(_scrollToBottomY);
于 2016-02-16T03:54:53.383 回答
24

这是我能想到的最简单的解决方案:

 <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
    });
}}
/>;
于 2016-04-22T20:43:01.823 回答
8

万一 2020 年或以后的任何人想知道如何使用功能组件来实现这一点。我就是这样做的:

ref={ref => scrollView = ref }
onContentSizeChange={() => scrollView.scrollToEnd({ animated: true })}>
于 2020-05-28T17:17:37.940 回答
6

试试这个解决方案

代码 10.0

注册护士:56.0.0

<ScrollView ref="scrollView"
             onContentSizeChange={(width,height) => this.refs.scrollView.scrollTo({y:height})}>  </ScrollView> // OR height -  width
于 2018-12-03T09:40:24.903 回答
6

react-native-invertible-scroll-view您可以使用模块反转滚动/列表视图,然后只需调用ref.scrollTo(0)滚动到底部。

安装模块:

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

然后导入组件:

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

然后使用以下 JSX 代替ScrollView

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

这是有效的,因为react-native-invertible-scroll-view翻转了整个视图的内容。请注意,视图的子视图也将以与普通视图相反的顺序呈现 - 第一个子视图将出现在底部

于 2015-08-27T03:11:20.860 回答
4

实际上@Aniruddha 答案对我不起作用,因为我正在使用"react-native": "0.59.8"并且this.scrollView.root.scrollToEnd未定义

但我想通了,这行得通this.scrollView.scrollResponderScrollToEnd({animated: true});

如果您正在使用0.59.8这将起作用,或者如果您使用的是更高版本并且这对您有用。请在此答案中添加版本,以免其他人遇到麻烦。

完整代码在这里

<ScrollView
    ref={ref => this.scrollView = ref}
    onContentSizeChange={(contentWidth, contentHeight)=>{        
        this.scrollView.scrollResponderScrollToEnd({animated: true});
    }}>
</ScrollView>
于 2019-11-22T10:57:55.180 回答
2

这种方法有点hacky,但我找不到更好的方法

  1. 首先向您的 ScrollView 添加一个引用。
  2. 在关闭 ScrollView 标签之前添加一个虚拟视图
  3. 获取该虚拟视图的 y 位置
  4. 每当您想滚动到底部时,滚动到虚拟视图的位置

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

于 2016-02-05T23:08:35.900 回答
1

如果你使用 TypeScript 你需要这样做

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>
于 2019-12-03T10:03:17.923 回答
1

这回答了你的问题: https ://stackoverflow.com/a/39563100/1917250

您需要通过计算内容的高度减去其滚动视图的高度来不断滚动到页面底部。

于 2016-09-18T22:17:55.517 回答
0

我想现在回答为时已晚,但我得到了一个 hack!如果您使用FlatList,您可以启用inverted回退到设置transform scale为的属性-1(这对于其他列表组件,如ScrollView...)是可以接受的。当你渲染你FlatList的数据时,它总是在底部!

于 2019-08-31T19:50:01.597 回答
0

我为此奋斗了一段时间,最后想出了一些对我来说非常有效和顺利的东西。像许多人一样,我试图.scrollToEnd无济于事。对我有用的解决方案是结合onContentSizeChange, onLayoutprops 和更多的视觉思考“滚动到底部”的真正含义。最后一部分现在对我来说似乎微不足道,但我花了很长时间才弄清楚。

鉴于ScrollView具有固定高度,当内容高度超过容器的高度时,我通过减去(内容高度)的prevHeight(固定高度ScrollView)来计算偏移量。currHeight如果您可以直观地想象它,滚动到 y 轴上的差异,将内容高度在其容器上滑动该偏移量。我增加了我的偏移量,使我现在的当前内容高度成为我以前的高度,并不断计算一个新的偏移量。

这是代码。希望它可以帮助某人。

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>
    );
  }
}
于 2019-02-23T10:38:32.780 回答
-2

尝试将滚动视图的contentOffset属性设置为内容的当前高度。

要完成您需要的操作,您可以在 onScroll 事件中执行此操作。但是,这可能会导致糟糕的用户体验,因此仅在附加新消息时才执行此操作可能会更加用户友好。

于 2015-05-17T13:00:19.357 回答
-2

我有一个类似的问题,但是在阅读了这个页面之后(这让我头疼!)我发现这个非常好的 npm 包它只是反转了 ListView 并使聊天应用程序的一切变得容易!

于 2017-04-25T18:41:21.503 回答
-4

有点晚了......但看看这个问题。滚动到 ScrollView 的顶部

ScrollView 有一个“scrollTo”方法。

于 2015-08-07T21:32:07.340 回答