IM 场景和普通场景下的 FlatList 的区别
聊天信息和普通的列表信息不一样,聊天信息列表需要最新的聊天消息显示在最底部,初始展现的聊天信息是最新的聊天信息,同时,如果消息数目不够占满屏幕,整个 FlatList 应该在屏幕顶部。
实现 IM 场景下 FlatList 的思路
添加 FlatList inverted
属性为 true
后,整个 FlatList 都翻转,包括了上拉下拉的回调函数也翻转了,现在上拉到顶实际会触发 onEndReached
回调。
当 invert FlatList 后,如果 items 数量不够占满屏幕,items 会出现在屏幕底部,设置 FlatList 的 contentContainerStyle
属性使 items 出现在屏幕顶部,注意 flexGrow: 1
会导致额外触发一次 onEndReached
:
contentContainerStyle={{
flexGrow: 1,
justifyContent: 'flex-end',
}}
效果展示:
完整的测试代码:
import {Text, FlatList, StyleSheet} from 'react-native';
import React, {useRef} from 'react';
/**
* 100 条历史消息,先给 10 条最新的,再给 10 条
* 也就是先给 91 - 100, 再给 81 - 90, 依次类推
*/
const getData = (page: number, size: number) => {
return new Promise<string[]>(resolve => {
setTimeout(() => {
const allData = [];
for (let i = 0; i < 200; i++) {
allData.push(`Message ${i}`);
}
allData.reverse();
const newRes = allData.slice(page * size, page * size + size).reverse();
resolve(newRes);
}, 1000);
});
};
const DetailScreen = () => {
/**
* 分页字段
* page
* size
* total,根据 total 判断是否还有更多数据
*/
const curPageRef = useRef(0);
const SIZE = 15;
const [data, setData] = React.useState<string[]>([]);
const handleOnEndReached = () => {
console.log(
'🚀 ~ file: DetailScreen.tsx:53 ~ handleOnEndReached ~ handleOnEndReached:',
handleOnEndReached,
);
getData(curPageRef.current, SIZE).then(res => {
res.reverse();
setData([...data, ...res]);
});
curPageRef.current += 1;
};
return (
<>
<FlatList
onEndReached={handleOnEndReached}
style={{flex: 1}}
contentContainerStyle={{
flexGrow: 1,
justifyContent: 'flex-end',
}}
inverted
data={data}
renderItem={({item}) => <Text style={styles.message}>{item}</Text>}
keyExtractor={item => item}
/>
</>
);
};
const styles = StyleSheet.create({
message: {
fontSize: 30,
flex: 1,
margin: 10,
backgroundColor: '#FFF',
},
});
export default DetailScreen;