【问题标题】:React native flatlist initial scroll to bottom反应原生平面列表初始滚动到底部
【发布时间】:2018-07-06 17:54:18
【问题描述】:

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

与 WhatsApp 和其他聊天应用一样,消息从底部开始。

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

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

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

如何最初滚动到底部?

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

【问题讨论】:

    标签: react-native chat react-native-flatlist


    【解决方案1】:

    我猜测 RN 无法猜测您的布局,因此它无法知道需要“移动”多少。根据文档中的滚动方法,您可能需要实现一个 getItemLayout 函数,因此 RN 可以知道它需要滚动多少。

    https://facebook.github.io/react-native/docs/flatlist.html#scrolltoend

    【讨论】:

      【解决方案2】:

      我遇到了同样的问题,然后我转而使用 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 的问题中
      【解决方案3】:

      我有类似的问题。如果你想让你的聊天消息从底部开始,你可以将“inverted”设置为true,并以相反的方向显示你的消息和时间标签。

      在此处查看 FlatList 的“倒置”属性。 https://facebook.github.io/react-native/docs/flatlist#inverted

      如果你想让你的聊天消息从顶部开始,这就是我想要实现的。我在 FlatList 中找不到解决方案,因为正如你所说,高度不同,我无法使用 getItemLayout,这会使“scrollToEnd”行为异常。

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

      【讨论】:

      • 我使用了您的倒置解决方案并将 flex-direction 更改为 column-reverse。现在它按预期工作:&lt;FlatList data={messages} inverted contentContainerStyle={{ flexDirection: 'column-reverse' }} /&gt;
      • @Johnny Fekete 这实际上以相反的顺序呈现列表。你设法扭转了名单吗?还是您找到了更好的方法?
      • 非常感谢@JohnnyFekete先生
      • 起初这对我有用,然后我尝试渲染许多聊天消息,并且在挂载时会产生奇怪的滚动效果,这是由flexDirection: 'column-reverse'.引起的,而不是在数据数组中调用reverse()不是性能最佳,但似乎是无故障的解决方案
      【解决方案4】:

      initialScrollIndex 设置为数据集的长度 - 1。

      <Flatlist
      data={dataSet}
      initialScrollIndex={dataSet.length - 1}
      />
      

      【讨论】:

      • 出现异常错误:scrollToIndex should be used in conjunction with getItemLayout or onScrollToIndexFailed
      【解决方案5】:

      如果你想让 FlatList 在初始渲染时滚动到底部。刚刚将 reverse={-1} 添加到您的 FlatList 中。我在滚动到底部的过程中挣扎了几个小时,但最终以倒置 = {-1} 结束。无需考虑使用 getItemLayout 和 initialScrollIndex 等动态测量 FlatList 项的高度。

      【讨论】:

      • 这行不通,因为你只会反转所有内容
      • 这似乎适用于 iOS,但对于 Android,它会颠倒项目的顺序......
      【解决方案6】:

      【讨论】:

        【解决方案7】:

        我也在这方面苦苦挣扎,并为我找到了无故障渲染的最佳解决方案是:

        1. 使用inverted={-1} 道具
        2. 使用 reverse() javascript 函数使用 data={MyArrayofMessages.reverse()} 在我的情况下为 data={this.state.messages.reverse()} 反转数组中消息对象的顺序。

        简单到可以即时渲染!

        【讨论】:

        • 如果他想使用 Array.reverse();他不想使用倒置的平面列表。因为 Array.reverse() 需要时间来处理
        【解决方案8】:

        使用 inverted={1} 并使用 JS 反转功能 反转您的数据。它对我有用

        【讨论】:

          【解决方案9】:

          如果你想反转显示消息,在平面列表中将“inverted”设置为true。

          <Flatlist
          data={messageData}
          inverted={true}
          horizontal={false}
          />
          

          如果只想滚动到最后一条消息,可以使用initialScrollIndex

          <Flatlist
          data={messageData}
          initialScrollIndex={messageArray.length - 1}
          horizontal={false}
          />
          

          【讨论】:

          • 这个解决方案总是抛出:Invariant Violation: scrollToIndex 应该和getItemLayout或者onScrollToIndexFailed一起使用,否则无法知道离屏索引的位置或者处理失败。
          【解决方案10】:

          我找到了一个 100% 适合我的解决方案

          将 ref 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
          • 反应 17.0.2

          【讨论】:

            【解决方案11】:

            截至 2021 年,有两种“良好”的解决方案。 第一个是超时、引用和 useEffect。这是使用功能组件和 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 } 
               />
            
            

            【讨论】:

              【解决方案12】:

              我用反转属性和反转函数解决了这个问题

              https://facebook.github.io/react-native/docs/flatlist#inverted

              https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reverse

              <FlatList
                 inverted
                 data={[...data].reverse()}
                 renderItem={renderItem}
                 keyExtractor={(item) => item.id}
              />
              

              您可以在聊天组件中使用此解决方案。

              【讨论】:

                【解决方案13】:

                我花了几个小时努力在顶部显示第一条消息,但无法计算项目的高度,因为它包含链接和消息。但最后我已经能够...

                我所做的是我将FlatList 包装在View 中,将FlatList 设置为倒置,使其占用所有可用空间,然后调整内容。所以现在,消息很少的对话从顶部开始,但是当有多个消息时,它们将在底部结束。像这样的:

                <View style={ConversationStyle.container}>
                    <FlatList
                        data={conversations}
                        initialNumToRender={10}
                        renderItem={({ item }) => (
                            <SmsConversationItem
                                item={item}
                                onDelete={onDelete}
                            />
                        )}
                        keyExtractor={(item) => item.id}
                        getItemCount={getItemCount}
                        getItem={getItem}
                        contentContainerStyle={ConversationStyle.virtualizedListContainer}
                        inverted // This will make items in reversed order but will make all of them start from bottom
                    />
                </View>
                

                而我的风格是这样的:

                const ConversationStyle = StyleSheet.create({
                    container: {
                        flex: 1
                    },
                
                    virtualizedListContainer: {
                        flexGrow: 1,
                        justifyContent: 'flex-end'
                    }
                };
                
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多