如何用React Native FlatList实现带日期分隔的WhatsApp风格聊天UI
实现React Native FlatList消息中插入日期分隔(仿WhatsApp)
核心思路
先把原始消息数组转换成包含日期分隔项的混合数组,再让FlatList根据项的类型分别渲染日期或消息内容。
步骤1:处理原始消息数据
写一个工具函数,遍历消息数组,对比当前消息和上一条消息的日期,若日期不同则插入日期分隔项。这里用原生Intl.DateTimeFormat格式化日期,无需额外依赖:
// 格式化时间戳为日期字符串(仅年月日部分) const formatDate = (timestamp) => { return new Intl.DateTimeFormat('zh-CN', { year: 'numeric', month: 'long', day: 'numeric' }).format(new Date(timestamp)); }; // 处理消息数组,插入日期分隔项 const processMessagesWithDates = (messages) => { if (!messages.length) return []; const processed = []; let lastDate = null; messages.forEach((msg) => { const currentDate = formatDate(msg.timestamp); // 如果当前消息日期和上一条不同,插入日期项 if (currentDate !== lastDate) { processed.push({ type: 'date', content: currentDate }); lastDate = currentDate; } // 加入原始消息,标记类型为message processed.push({ type: 'message', content: msg }); }); return processed; };
步骤2:用FlatList渲染混合数组
在组件中调用处理函数,让FlatList根据item的类型渲染不同内容:
import { View, Text, FlatList, StyleSheet } from 'react-native'; const ChatScreen = ({ messages }) => { const processedData = processMessagesWithDates(messages); const renderItem = ({ item }) => { if (item.type === 'date') { // 渲染日期分隔组件 return ( <View style={styles.dateContainer}> <Text style={styles.dateText}>{item.content}</Text> </View> ); } // 渲染普通消息组件(替换成你自己的消息UI即可) const msg = item.content; return ( <View style={msg.isMine ? styles.myMessage : styles.otherMessage}> <Text style={msg.isMine ? styles.myText : styles.otherText}>{msg.content}</Text> <Text style={styles.timeText}> {new Intl.DateTimeFormat('zh-CN', { hour: '2-digit', minute: '2-digit' }).format(new Date(msg.timestamp))} </Text> </View> ); }; return ( <FlatList data={processedData} renderItem={renderItem} keyExtractor={(item, index) => index.toString()} contentContainerStyle={styles.listContainer} inverted={true} // 消息底部最新时开启反转 /> ); }; // 仿WhatsApp风格的样式参考 const styles = StyleSheet.create({ listContainer: { paddingVertical: 10, paddingHorizontal: 15, }, dateContainer: { alignItems: 'center', marginVertical: 12, }, dateText: { backgroundColor: '#e9e9eb', color: '#666', paddingVertical: 4, paddingHorizontal: 12, borderRadius: 8, fontSize: 12, }, myMessage: { alignSelf: 'flex-end', backgroundColor: '#dcf8c6', borderRadius: 18, padding: 10, marginVertical: 4, maxWidth: '75%', }, otherMessage: { alignSelf: 'flex-start', backgroundColor: '#fff', borderRadius: 18, padding: 10, marginVertical: 4, maxWidth: '75%', }, myText: { fontSize: 14, color: '#000', }, otherText: { fontSize: 14, color: '#000', }, timeText: { fontSize: 11, color: '#666', alignSelf: 'flex-end', marginTop: 4, }, });
注意事项
- 如果消息是按时间倒序排列,开启
inverted属性后,建议先反转原始数组处理日期,再反转回倒序,避免日期判断逻辑出错。 - 若要更精准判断跨天边界,可以把时间戳转换为当天0点的时间戳来对比,避免时分秒差异导致的误判。
- 样式可根据自身UI需求调整,核心是保证日期项居中显示的布局逻辑。
内容的提问来源于stack exchange,提问作者React_Coder
相关产品推荐
相关产品推荐

