Browse Source
feat(message): 实现消息时间显示和消息项组件化
feat(message): 实现消息时间显示和消息项组件化
- 将聊天页面中的消息项构建逻辑提取为独立的 MessageItem 组件- 添加消息时间显示功能,超过20分钟间隔则显示时间标签 - 支持今天、昨天和其他日期的时间格式化显示- 优化消息气泡样式,区分发送方和接收方背景色与文字颜色 - 移除聊天页面中原有的消息构建方法,使用新组件替代 -修复消息列表中时间戳显示不准确的问题ios
2 changed files with 163 additions and 71 deletions
Split View
Diff Options
@ -0,0 +1,155 @@ |
|||
import 'package:flutter/material.dart'; |
|||
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
|||
import 'package:im_flutter_sdk/im_flutter_sdk.dart'; |
|||
|
|||
import '../../../generated/assets.dart'; |
|||
|
|||
class MessageItem extends StatelessWidget { |
|||
final EMMessage message; |
|||
final bool isSentByMe; |
|||
final EMMessage? previousMessage; |
|||
|
|||
const MessageItem({ |
|||
required this.message, |
|||
required this.isSentByMe, |
|||
this.previousMessage, |
|||
super.key, |
|||
}); |
|||
|
|||
@override |
|||
Widget build(BuildContext context) { |
|||
// 只处理文本消息,其他类型消息可以根据需要扩展 |
|||
if (message.body.type == MessageType.TXT) { |
|||
final textBody = message.body as EMTextMessageBody; |
|||
return Column( |
|||
children: [ |
|||
// 显示时间(如果距离上一条消息超过20分钟) |
|||
if (shouldShowTime()) _buildTimeLabel(), |
|||
Container( |
|||
padding: EdgeInsets.symmetric( |
|||
horizontal: 16.w, |
|||
vertical: 8.h, |
|||
), |
|||
child: Row( |
|||
mainAxisAlignment: isSentByMe ? MainAxisAlignment.end : MainAxisAlignment.start, |
|||
crossAxisAlignment: CrossAxisAlignment.start, |
|||
children: [ |
|||
if (!isSentByMe) _buildAvatar(), |
|||
if (!isSentByMe) SizedBox(width: 8.w), |
|||
Container( |
|||
constraints: BoxConstraints(maxWidth: 240.w), |
|||
margin: EdgeInsets.only(top: 10.h), |
|||
padding: EdgeInsets.symmetric( |
|||
horizontal: 12.w, |
|||
vertical: 8.h, |
|||
), |
|||
decoration: BoxDecoration( |
|||
color: isSentByMe ? Color(0xff8E7BF6) : Colors.white, // 修改为紫色和白色 |
|||
borderRadius: BorderRadius.only( |
|||
topLeft: isSentByMe ? Radius.circular(12.w) : Radius.circular(0), |
|||
topRight: isSentByMe ? Radius.circular(0) : Radius.circular(12.w), |
|||
bottomLeft: Radius.circular(12.w), |
|||
bottomRight: Radius.circular(0), |
|||
), |
|||
), |
|||
child: Text( |
|||
textBody.content, |
|||
style: TextStyle( |
|||
fontSize: 14.sp, |
|||
color: isSentByMe ? Colors.white : Colors.black, // 发送方白色文字,接收方黑色文字 |
|||
), |
|||
), |
|||
), |
|||
if (isSentByMe) SizedBox(width: 8.w), |
|||
if (isSentByMe) _buildAvatar(), |
|||
], |
|||
), |
|||
), |
|||
], |
|||
); |
|||
} |
|||
|
|||
// 非文本消息显示占位符 |
|||
return Column( |
|||
children: [ |
|||
if (shouldShowTime()) _buildTimeLabel(), |
|||
Container( |
|||
padding: EdgeInsets.symmetric( |
|||
horizontal: 16.w, |
|||
vertical: 8.h, |
|||
), |
|||
child: Text('不支持的消息类型'), |
|||
), |
|||
], |
|||
); |
|||
} |
|||
|
|||
// 判断是否需要显示时间 |
|||
bool shouldShowTime() { |
|||
if (previousMessage == null) { |
|||
return true; // 第一条消息显示时间 |
|||
} |
|||
|
|||
// 判断距离上一条消息是否超过20分钟(1200000毫秒) |
|||
return (message.serverTime - previousMessage!.serverTime) > 1200000; |
|||
} |
|||
|
|||
// 构建时间标签 |
|||
Widget _buildTimeLabel() { |
|||
final formattedTime = formatMessageTime(message.serverTime); |
|||
|
|||
return Container( |
|||
alignment: Alignment.center, |
|||
padding: EdgeInsets.symmetric( |
|||
horizontal: 16.w, |
|||
), |
|||
child: Container( |
|||
padding: EdgeInsets.symmetric( |
|||
horizontal: 12.w, |
|||
), |
|||
child: Text( |
|||
formattedTime, |
|||
style: TextStyle( |
|||
fontSize: 12.sp, |
|||
color: Colors.grey, |
|||
), |
|||
), |
|||
), |
|||
); |
|||
} |
|||
|
|||
// 格式化消息时间 |
|||
String formatMessageTime(int timestamp) { |
|||
final date = DateTime.fromMillisecondsSinceEpoch(timestamp); |
|||
final now = DateTime.now(); |
|||
final today = DateTime(now.year, now.month, now.day); |
|||
final yesterday = DateTime(now.year, now.month, now.day - 1); |
|||
final messageDate = DateTime(date.year, date.month, date.day); |
|||
|
|||
if (messageDate.isAtSameMomentAs(today)) { |
|||
// 今天的消息显示时间 |
|||
return '今天 ${date.hour.toString().padLeft(2, '0')}:${date.minute.toString().padLeft(2, '0')}'; |
|||
} else if (messageDate.isAtSameMomentAs(yesterday)) { |
|||
// 昨天的消息 |
|||
return '昨天 ${date.hour.toString().padLeft(2, '0')}:${date.minute.toString().padLeft(2, '0')}'; |
|||
} else { |
|||
// 其他日期显示完整日期和时间 |
|||
return '${date.month}月${date.day}日 ${date.hour.toString().padLeft(2, '0')}:${date.minute.toString().padLeft(2, '0')}'; |
|||
} |
|||
} |
|||
|
|||
// 构建头像 |
|||
Widget _buildAvatar() { |
|||
return Container( |
|||
width: 40.w, |
|||
height: 40.w, |
|||
decoration: BoxDecoration( |
|||
borderRadius: BorderRadius.circular(20.w), |
|||
image: DecorationImage( |
|||
image: AssetImage(Assets.imagesAvatarsExample), |
|||
fit: BoxFit.cover, |
|||
), |
|||
), |
|||
); |
|||
} |
|||
} |
|||
Write
Preview
Loading…
Cancel
Save