React Native FlatList初始滚动到底部

39

我正在尝试使用 <Flatlist /> 在 React Native 中创建一个聊天室。

就像 WhatsApp 和其他聊天应用一样,消息从底部开始显示。

从我的 API 获取消息后,我调用

this.myFlatList.scrollToEnd({animated: false});

但它有时会在中间滚动,有时底部的项目较少,有时什么也不做。

我如何最初将其滚动到底部?

我的聊天消息高度不同,因此无法计算高度。

16个回答

47

我遇到了类似的问题。如果你希望聊天消息从底部开始显示,可以将 "inverted" 设置为 true,然后将你的消息和时间标签以相反的方向显示。

在这里查看 FlatList 的 "inverted" 属性。 https://facebook.github.io/react-native/docs/flatlist#inverted

如果你希望聊天消息从顶部开始显示,这也是我想要实现的。因为像你所说的,高度不同,所以我无法在 FlatList 中找到解决方案。我不能使用 getItemLayout,因为它会使 "scrollToEnd" 以奇怪的方式表现。

我采用了 @My Mai 提到的方法,而是使用 ScrollView,并在 setTimeout 函数中执行 scrollToEnd({animated: false})。此外,我添加了一个状态来隐藏内容,直到 scrollToEnd 完成,这样用户就不会看到任何滚动。


31
我使用了你的倒置解决方案,并将flex-direction改为column-reverse。现在它按预期工作: <FlatList data={messages} inverted contentContainerStyle={{ flexDirection: 'column-reverse' }} /> - Johnny Fekete
@Johnny Fekete,实际上这将以相反的顺序呈现列表。您成功地反转了列表吗?或者您找到了更好的方法? - Josh Liu
1
非常感谢JohnnyFekete先生。 - Rafiq
1
一开始这对我起作用,但是当我尝试渲染许多聊天消息时,它在挂载时产生了奇怪的滚动效果,这是由于flexDirection: 'column-reverse'引起的。相反,在数据数组中调用reverse()虽然不是最佳性能,但似乎是没有故障的解决方案。 - fermmm
如果我有一个非常大的列表怎么办?当我使用列反转时,它加载非常缓慢且明显,看起来很糟糕。 - Arcanus

22

谢谢你的解决方案!它非常好用 :) - Teo
这对我来说完美地运作了。 - Badr B
简短、精确、神奇。谢谢,伙计。 - Andrew Mititi
使用“倒置”似乎会显著影响性能。 - Rob
使用“倒置”似乎会显著影响性能。 - undefined

12
将“initialScrollIndex”设置为数据集的长度减1。
即,
<Flatlist
data={dataSet}
initialScrollIndex={dataSet.length - 1}
/>

18
在这段代码中出现了异常错误:“scrollToIndex应该与getItemLayout或onScrollToIndexFailed一起使用”。 - douglasrcjames

8

我曾经和你一样遇到了同样的问题,后来我开始使用ScrollView。现在问题解决了:

componentDidMount() {
  setTimeout(() => {
    this.scrollView.scrollToEnd();
  });
}

<ScrollView ref={(ref) => { this.scrollView = ref; }} style={styles.messages}>
      {
        messages.map((item, i) => (
          <Message 
            key={i} 
            direction={item.userType === 'banker' ? 'right' : 'left'} 
            text={item.message} 
            name={item.name}
            time={item.createdAt}
          />
        ))
      }
    </ScrollView>`

在这个问题中需要使用FlatList。 - fermmm

6

截至2021年,有两种“好”的解决方案。 第一种是使用timeout、references和useEffect。以下是使用Functional Components和Typescript的完整示例:

   // Set the height of every item of the list, to improve perfomance and later use in the getItemLayout
   const ITEM_HEIGHT = 100;

   // Data that will be displayed in the FlatList
   const [data, setData] = React.useState<DataType>();

   // The variable that will hold the reference of the FlatList
   const flatListRef = React.useRef<FlatList>(null);

   // The effect that will always run whenever there's a change to the data
   React.useLayoutEffect(() => {
    const timeout = setTimeout(() => {
      if (flatListRef.current && data && data.length > 0) {
        flatListRef.current.scrollToEnd({ animated: true });
      }
    }, 1000);

    return () => {
      clearTimeout(timeout);
    };

   }, [data]);

   // Your FlatList component that will receive ref, data and other properties as needed, you also have to use getItemLayout
   <FlatList
     data={data}
     ref={flatListRef}
     getItemLayout={(data, index) => {
              return { length: ITEM_HEIGHT, offset: ITEM_HEIGHT * index, index };
     }}
     { ...otherProperties } 
   />

通过上面的示例,您可以实现流畅而有动画效果的滚动到底部。例如,在接收新消息并需要滚动到底部时推荐使用。

除此之外,第二种更简单的方法是通过实现initialScrollIndex属性,该属性将立即在底部加载列表,就像您提到的聊天应用程序一样。当首次打开聊天屏幕时,它将正常工作。

像这样:

   // No need to use useEffect, timeout and references... 
   // Just use getItemLayout and initialScrollIndex.

   // Set the height of every item of the list, to improve perfomance and later use in the getItemLayout
   const ITEM_HEIGHT = 100;

   <FlatList
     data={data}
     getItemLayout={(data, index) => {
       return { length: ITEM_HEIGHT, offset: ITEM_HEIGHT * index, index }; 
     }}
     { ...otherProperties } 
   />


2

我找到了一个对我百分之百有效的解决方案。

在我的平面列表中添加了引用flatListRef

<Flatlist
     reference={(ref) => this.flatListRef = ref}
     data={data}
     keyExtractor={keyExtractor}
     renderItem={renderItem}
/>

当你想要自动滚动到列表底部时,请使用以下方法:

this.flatListRef._listRef._scrollRef.scrollToEnd({ animating: true });

是的,您应该访问元素 _listRef,然后访问 _scrollRef,最后调用 scrollToEnd


  • react-native 版本为 0.64.1
  • react 版本为 17.0.2


1
我找到了一个对我百分之百有效的解决方案。
  let scrollRef = React.useRef(null)

并且

<FlatList
   ref={(it) => (scrollRef.current = it)}
   onContentSizeChange={() =>
        scrollRef.current?.scrollToEnd({animated: false})
    }
    data={data}/>

1

使用 inverted={1} 并使用 JS反转函数 反转您的数据。这对我有用。


1

我也曾为此苦恼,但是我找到了对我来说最好的解决方案,没有任何故障:

  1. 使用 inverted={-1} 属性
  2. 使用 JavaScript 的 reverse() 函数反转数组中消息对象的顺序,例如在我的情况下使用 data={this.state.messages.reverse()} 中的 data={MyArrayofMessages.reverse()}

非常简单,瞬间呈现!


如果他想使用Array.reverse(),他不想使用倒置的flatlist。因为Array.reverse()需要时间处理。 - ucup

1

<FlatList contentContainerStyle={{ flex: 1, justifyContent: 'flex-end' }} />

这段代码是关于编程的,它用于创建一个名为FlatList的组件,并设置了contentContainerStyle属性。该属性中包含了一个flex属性和一个justifyContent属性,用于控制组件的布局和对齐方式。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接