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

Posted

技术标签:

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

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

【问题讨论】:

我对 react-native 一无所知,但请记住,有时用户希望向上滚动查看聊天记录。确保只有在新消息到达时聊天已经滚动到底部时才滚动聊天。 这是个好主意。我们在此处跟踪此问题:github.com/facebook/react-native/issues/107 我刚刚回答了一个类似的问题,请在这里查看——***.com/a/32652967/1541508 这能回答你的问题吗? How to scroll to bottom of React Native ListView 【参考方案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 想要的)。请参阅***.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,但我找不到更好的方法

    首先向 ScrollView 添加一个引用。 在关闭 ScrollView 标记之前第二次添加一个虚拟视图 获取该虚拟视图的 y 位置 当你想滚动到底部时,滚动到虚拟视图的位置

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://***.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 无济于事。对我有用的解决方案是onContentSizeChangeonLayout 道具的组合,并在视觉上更多地思考“滚动到底部”的真正含义。最后一部分现在对我来说似乎微不足道,但我花了很长时间才弄清楚。

鉴于ScrollView 具有固定高度,当内容高度超过容器高度时,我通过减去currHeightprevHeightScrollView 的固定高度)来计算偏移量(内容高度)。如果您可以直观地想象它,滚动到 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 并使聊天应用程序的一切变得简单!

【讨论】:

-1;这与a previously posted answer here 重复(也有点困惑;这个问题是关于ScrollView,而不是`ListView`)。【参考方案16】:

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

ScrollView 有一个“scrollTo”方法。

【讨论】:

是的,ScrollView上有一个scrollTo方法,但是问题是专门询问滚动到底部,这并不简单。

以上是关于是否可以让 ScrollView 滚动到底部?的主要内容,如果未能解决你的问题,请参考以下文章

如何以编程方式将 ScrollView 滚动到底部

SwiftUI - ScrollView 没有一直滚动到底部

如何让ScrollView 的滚动条不显示

Android:在键盘显示中,将 ScrollView 固定到底部

解决ScrollView自动滚动到底部的问题

如何确定 div 是不是滚动到底部?