我正在尝试使用
<Flatlist />
在 React Native 中创建聊天
与 WhatsApp 和其他聊天应用程序一样,消息从底部开始。
从 API 获取消息后,我调用
this.myFlatList.scrollToEnd({animated: false});
但它会滚动到中间的某个位置,有时底部的项目较少,有时什么也不做。
如何首先滚动到底部?
我的聊天消息有不同的高度,所以我无法计算高度。
我也有类似的问题。如果您想让聊天消息从底部开始,您可以将“inverted”设置为 true 并以相反的方向显示您的消息和时间标签。
在此处检查 FlatList 的“inverted”属性。 https://facebook.github.io/react-native/docs/flatlist#inverted
如果你想让聊天消息从顶部开始,这就是我想要实现的目标。我无法在 FlatList 中找到解决方案,因为正如你所说,高度不同,我无法使用 getItemLayout 这使得“scrollToEnd”以一种奇怪的方式表现。
我遵循@My Mai提到的方法,使用ScrollView代替,并在setTimeout函数中执行scrollToEnd({animated: false})。此外,我添加了一个状态来隐藏内容,直到scrollToEnd完成,这样用户就不会看到任何滚动。
我用倒置属性和反向函数解决了这个问题
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}
/>
您可以在聊天组件中使用此解决方案。
将
initialScrollIndex
设置为数据集的长度 - 1。
即
<Flatlist
data={dataSet}
initialScrollIndex={dataSet.length - 1}
/>
我和你遇到了同样的问题,然后我转而使用 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>`
截至 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 }
/>
我找到了一个 100% 对我有用的解决方案
将参考文献
flatListRef
添加到我的平面列表中:
<Flatlist
reference={(ref) => this.flatListRef = ref}
data={data}
keyExtractor={keyExtractor}
renderItem={renderItem}
/>
然后,每当您想自动滚动到列表底部时,请使用:
this.flatListRef._listRef._scrollRef.scrollToEnd({ animating: true });
是的,您应该访问元素 _listRef 然后访问 _scrollRef 然后调用 scrollToEnd 🙄
我也一直在努力解决这个问题,并发现对我来说最好的渲染无故障的解决方案是:
inverted={-1}
道具data={MyArrayofMessages.reverse()}
反转数组中消息对象的顺序。
并使用 JS 反转函数反转数据。它对我有用
data={this.state.messages.reverse()}
和
let scrollRef = React.useRef(null)
<FlatList
ref={(it) => (scrollRef.current = it)}
onContentSizeChange={() =>
scrollRef.current?.scrollToEnd({animated: false})
}
data={data}/>
如果只想滚动到最后一条消息,可以使用initialScrollIndex
<Flatlist
data={messageData}
inverted={true}
horizontal={false}
/>
我所做的是将
<Flatlist
data={messageData}
initialScrollIndex={messageArray.length - 1}
horizontal={false}
/>
包裹在
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>