是否可以将ScrollView滚动到底部?


87

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


3
我对“本机”一无所知,但请记住,有时用户会弯腰向上滚动以查看聊天记录。确保只有在新消息到达时聊天已经一直滚动到底部时,才滚动聊天。
大卫

这是一个好主意。我们正在此处跟踪此问题:github.com/facebook/react-native/issues/107
Eric Vicenti

我刚刚回答了类似的问题,请在此处进行检查– stackoverflow.com/a/32652967/1541508
Kohver,2015年

这回答了你的问题了吗?如何滚动到React Native ListView的底部
TripleM

Answers:


165

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

<ScrollView
    ref={ref => {this.scrollView = ref}}
    onContentSizeChange={() => this.scrollView.scrollToEnd({animated: true})}>
</ScrollView>

3
从本机0.55.4及更高版本开始,我不得不使用root否则,scrollToEnd是未定义的。即this.scrollView.root.scrollToEnd
Simon

4
当前使用react native 0.58.6并使用root实际上会引发未定义的错误。
Jose Bernhardt

1
应该是这样:ref={ref => {this.scrollView = ref}}因为您不想返回作业
Hampycalc

25

使用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);

2
请注意,这会将视图完全滚动到底部,因此视图基本上是不可见的(除非您在测量后向其中添加了一些内容)。这是有道理的,因为代码滚动到可滚动区域的高度,而不是滚动到溢出可滚动区域的子代的高度(可能不是OP想要的高度)。请参阅stackoverflow.com/a/39563193/1526986
xixixao

20

这是我可以召集的最简单的解决方案:

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

1
当我使用此答案或其他类似答案时,它会使列表中的项目消失(看起来好像滚动太远了,但我不确定)。稍微滚动一下,一切都会重新出现,并且看起来好像又滑回了视线(因此,滚动理论太过夸张了)。任何明显的想法为什么会这样?
tscizzle 2016年

11

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

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

5

试试这个解决方案

的Xcode 10.0

RN:56.0.0

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

为什么ref=呢?似乎像是一个网络开发者的遗物
YungGun

5

如果有人在2020年或更晚的时候想知道如何使用功能组件来实现这一目标。这是我做的:

ref={ref => scrollView = ref }
onContentSizeChange={() => scrollView.scrollToEnd({ animated: true })}>

注意:您可以提及您正在使用useref。大多数人不知道如何使用带钩子的ref。
ʎzɐɹƆ

是。事实是,即使不使用useRef钩子,它也能解决问题。但是正确的方法是使用它!您说得对
Marlon Englemam

4

您可以使用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翻转了整个视图的内容。请注意,视图的子级也将以与普通视图相反的顺序进行渲染-第一个子级将出现在底部


3

实际上,@ 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>

1

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

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


这不完全是要求的。点击时滚动到底部,而不是在添加内容时使滚动视图滚动到底部。无论如何,scrollToBottom在新版本的React Native中已经淘汰了这种方法。
Mark Amery

1

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

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


这是对问题的正确答案。您可以知道何时执行滚动,链接中的答案显示了如何获取所需的号码。特别是,如果要将组件添加到列表中,则在调用componentDidUpdate时,内容高度将不包括它们,因此您要记住要滚动滚动onContentSizeChange。
xixixao

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>

0

我为此奋斗了一段时间,最后想出了对我来说非常有效和流畅的东西。像许多人一样,我.scrollToEnd也无济于事。为我工作的解决方案是一个组合onContentSizeChangeonLayout有用道具和一些视觉上思考“滚动到底”含义的组合。现在对我而言,最后一部分似乎微不足道,但我花了很长时间才弄清楚。

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

0

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


-1

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

要完成您需要的操作,可以将其作为onScroll事件的一部分。但是,这可能会带来不良的用户体验,因此只有在附加新消息时才这样做,可能会变得更加用户友好。


-1; 不。像这里的许多答案一样,这具有将内容ScrollView向下滚动到其所有内容下方的作用,而不仅仅是向下滚动至底部。
Mark Amery


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.