Browse Source
feat(message): 实现图片消息展示功能- 新增 ImageItem 组件用于展示图片消息
feat(message): 实现图片消息展示功能- 新增 ImageItem 组件用于展示图片消息
- 支持网络图片加载与错误处理 - 添加图片尺寸自适应逻辑- 优化消息气泡样式与布局 - 移除模拟推荐用户列表代码- 删除 IM 登录后的测试消息发送逻辑ios
4 changed files with 214 additions and 135 deletions
Split View
Diff Options
-
1lib/im/im_manager.dart
-
73lib/pages/message/conversation_tab.dart
-
195lib/widget/message/image_item.dart
-
80lib/widget/message/message_item.dart
@ -0,0 +1,195 @@ |
|||
import 'dart:io'; |
|||
import 'package:dating_touchme_app/generated/assets.dart'; |
|||
import 'package:flutter/material.dart'; |
|||
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
|||
import 'package:get/get.dart'; |
|||
import 'package:im_flutter_sdk/im_flutter_sdk.dart'; |
|||
|
|||
class ImageItem extends StatelessWidget { |
|||
final EMImageMessageBody imageBody; |
|||
final bool isSentByMe; |
|||
final bool showTime; |
|||
final String formattedTime; |
|||
|
|||
const ImageItem({ |
|||
required this.imageBody, |
|||
required this.isSentByMe, |
|||
required this.showTime, |
|||
required this.formattedTime, |
|||
super.key, |
|||
}); |
|||
|
|||
@override |
|||
Widget build(BuildContext context) { |
|||
return Column( |
|||
children: [ |
|||
// 显示时间 |
|||
if (showTime) _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( |
|||
margin: EdgeInsets.only(top: 10.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(12.w), |
|||
), |
|||
), |
|||
child: _buildImage(), |
|||
), |
|||
if (isSentByMe) SizedBox(width: 8.w), |
|||
if (isSentByMe) _buildAvatar(), |
|||
], |
|||
), |
|||
), |
|||
], |
|||
); |
|||
} |
|||
|
|||
// 构建时间标签 |
|||
Widget _buildTimeLabel() { |
|||
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, |
|||
), |
|||
), |
|||
), |
|||
); |
|||
} |
|||
|
|||
// 构建头像 |
|||
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, |
|||
), |
|||
), |
|||
); |
|||
} |
|||
|
|||
// 构建图片 |
|||
Widget _buildImage() { |
|||
// 计算图片尺寸,限制最大宽度为200 |
|||
double maxWidth = 200.w; |
|||
double maxHeight = 200.w; |
|||
double width = maxWidth; |
|||
double height = maxHeight; |
|||
Get.log(imageBody.thumbnailLocalPath ?? ''); |
|||
// 如果有图片尺寸信息,根据比例调整 |
|||
if (imageBody.width != null && imageBody.width! > 0 && |
|||
imageBody.height != null && imageBody.height! > 0) { |
|||
final aspectRatio = imageBody.width! / imageBody.height!; |
|||
if (aspectRatio > 1) { |
|||
// 宽图 |
|||
width = maxWidth; |
|||
height = maxWidth / aspectRatio; |
|||
} else { |
|||
// 高图 |
|||
height = maxHeight; |
|||
width = maxHeight * aspectRatio; |
|||
} |
|||
} |
|||
|
|||
// 尝试显示网络缩略图 |
|||
if (imageBody.thumbnailRemotePath != null && imageBody.thumbnailRemotePath!.isNotEmpty) { |
|||
return Image.network( |
|||
imageBody.thumbnailRemotePath!, |
|||
width: width, |
|||
height: height, |
|||
fit: BoxFit.cover, |
|||
loadingBuilder: (context, child, loadingProgress) { |
|||
if (loadingProgress == null) return child; |
|||
return _buildLoadingContainer(width, height); |
|||
}, |
|||
errorBuilder: (context, error, stackTrace) { |
|||
return _buildErrorContainer(width, height); |
|||
}, |
|||
); |
|||
} |
|||
|
|||
// 尝试显示网络原图 |
|||
if (imageBody.remotePath != null && imageBody.remotePath!.isNotEmpty) { |
|||
return Image.network( |
|||
imageBody.remotePath!, |
|||
width: width, |
|||
height: height, |
|||
fit: BoxFit.cover, |
|||
loadingBuilder: (context, child, loadingProgress) { |
|||
if (loadingProgress == null) return child; |
|||
return _buildLoadingContainer(width, height); |
|||
}, |
|||
errorBuilder: (context, error, stackTrace) { |
|||
return _buildErrorContainer(width, height); |
|||
}, |
|||
); |
|||
} |
|||
|
|||
// 默认显示错误容器 |
|||
return _buildErrorContainer(width, height); |
|||
} |
|||
|
|||
// 构建加载中的容器 |
|||
Widget _buildLoadingContainer(double width, double height) { |
|||
return Container( |
|||
width: width, |
|||
height: height, |
|||
padding: EdgeInsets.all(8.w), |
|||
decoration: BoxDecoration( |
|||
borderRadius: BorderRadius.circular(8.w), |
|||
color: Colors.grey[200], |
|||
), |
|||
alignment: Alignment.center, |
|||
child: CircularProgressIndicator( |
|||
strokeWidth: 2.w, |
|||
color: Colors.grey[400], |
|||
), |
|||
); |
|||
} |
|||
|
|||
// 构建错误容器 |
|||
Widget _buildErrorContainer(double width, double height) { |
|||
return Container( |
|||
width: width, |
|||
height: height, |
|||
padding: EdgeInsets.all(8.w), |
|||
decoration: BoxDecoration( |
|||
borderRadius: BorderRadius.circular(8.w), |
|||
color: Colors.grey[200], |
|||
), |
|||
alignment: Alignment.center, |
|||
child: Icon( |
|||
Icons.image_not_supported, |
|||
size: 32.w, |
|||
color: Colors.grey[400], |
|||
), |
|||
); |
|||
} |
|||
} |
|||
Write
Preview
Loading…
Cancel
Save