【问题标题】:Is it possible to keep a ScrollView scrolled to the bottom?是否可以让 ScrollView 滚动到底部?
【发布时间】:2015-06-01 08:43:48
【问题描述】:

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

【问题讨论】:

标签: react-native


【解决方案1】:

对于 React Native 0.41 及更高版本,您可以使用内置的 scrollToEnd 方法来做到这一点:

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

【讨论】:

  • 从 react native 0.55.4 及更高版本开始,我必须使用 root 否则,scrollToEnd 未定义。即this.scrollView.root.scrollToEnd
  • 当前使用 react native 0.58.6 和使用 root 实际上会抛出未定义的错误。
  • 应该是:ref={ref =&gt; {this.scrollView = ref}},因为您不想返回作业
【解决方案2】:

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

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

【讨论】:

  • 简洁优雅。完美地做到了我想要的!谢谢!
  • 你是我的新英雄!!
  • 看起来很简单,但在我非常相似的用例中却不起作用。
【解决方案3】:

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

【讨论】:

  • 请注意,这会将视图完全滚动到底部,因此视图本质上是不可见的(除非您在测量后添加了一些东西)。这是有道理的,因为代码滚动到可滚动区域的高度,而不是滚动到溢出可滚动区域的孩子的高度(可能不是 OP 想要的)。请参阅stackoverflow.com/a/39563193/1526986。
【解决方案4】:

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

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

【讨论】:

  • 当我使用这个或其他类似的答案时,它会使列表中的项目消失(看起来它滚动 too 很远,但我不能确定)。滚动一点点会使所有内容重新出现,并且看起来像是滑回视野(因此滚动too理论)。任何明显的想法为什么会这样?
【解决方案5】:

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

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

【讨论】:

  • 注意:您可以提及您正在使用 userref。大多数人不知道如何将 ref 与钩子一起使用。
  • 是的。问题是即使不使用 useRef 钩子也能解决问题。但正确的方法是使用它!你是对的
【解决方案6】:

您可以使用react-native-invertible-scroll-view module 反转滚动/列表视图,然后只需调用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 翻转了整个视图的内容。请注意,视图的子视图也将以与普通视图相反的顺序呈现 - 第一个子视图将出现在 底部。

【讨论】:

    【解决方案7】:

    试试这个解决方案

    xcode 10.0

    RN:56.0.0

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

    【讨论】:

    • 为什么是ref=?看起来像一个网络开发遗物
    【解决方案8】:

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

    【讨论】:

      【解决方案9】:

      这个方法有点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>
          );
        }

      【讨论】:

      • 这不是完全所要求的;这会在点击时滚动到底部,而不是在添加内容时保持滚动视图滚动到底部。无论如何,scrollToBottom 使这种方法在新版本的 React Native 中过时了。
      【解决方案10】:

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

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

      【讨论】:

      • 这是问题的正确答案。您可以聪明地了解何时执行滚动,链接中的答案向您展示了如何获得所需的数字。特别是,如果您将组件添加到列表中,则在调用 componentDidUpdate 时内容高度将不包括它们,因此您要记住要滚动并在 onContentSizeChange 上滚动。
      【解决方案11】:

      如果你使用 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>
      

      【讨论】:

        【解决方案12】:

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

        【讨论】:

          【解决方案13】:

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

          鉴于ScrollView 具有固定高度,当内容高度超过容器高度时,我通过减去currHeight 的prevHeight(ScrollView 的固定高度)来计算偏移量(内容高度)。如果您可以直观地想象它,滚动到 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>
              );
            }
          }
          

          【讨论】:

            【解决方案14】:

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

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

            【讨论】:

            • -1;没有。与此处的许多答案一样,这具有将ScrollView 向下滚动到其所有内容下方的效果,而不仅仅是滚动到底部。
            【解决方案15】:

            我遇到了类似的问题,但是在阅读了这个页面后(这让我很头疼!)我发现 this very nice npm package 它只是反转了 ListView 并使聊天应用程序的一切变得简单!

            【讨论】:

            【解决方案16】:

            有点晚了……但是看看这个问题。 Scroll to top of ScrollView

            ScrollView 有一个“scrollTo”方法。

            【讨论】:

            • 是的,ScrollView上有一个scrollTo方法,但是问题是专门询问滚动到底部,这并不简单。
            猜你喜欢
            • 1970-01-01
            • 2011-02-19
            • 2013-02-14
            • 1970-01-01
            • 2014-08-15
            • 1970-01-01
            • 1970-01-01
            • 2020-03-26
            • 1970-01-01
            相关资源
            最近更新 更多