前言
最近写flutter项目,其中就有群聊的相关功能,我们需要实现群头像的拼接,这时候就需要把几个用户的头像按照一定的规则排列起来;
一、需要实现的效果如下
1、UI设计图:
二、flutter实现代码如下:
1、重点是RoomAvatarPainter画头像的代码
2、如果还不明白的朋友可以私信问我
class AvatarImageUtil {
static Future<String?> generateAvatarPath(List<String?> avatars) async {
final String key = Md5Util.stringToMd5(avatars.length > 9 ? avatars.sublist(0, 9).join('-') : avatars.join('-'));
var newFile = await FileDirUtils.generateManageDirFile(FileDirUtils.avatarDir, "png", fileName: key);
if (newFile.existsSync()) {
return newFile.path;
}
var path = newFile.path;
final List<ui.Image> images = [];
for (final element in avatars) {
final image = await _download(element);
images.add(image);
}
final recorder = ui.PictureRecorder();
final canvas = Canvas(recorder);
const imageSize = 320.0;
RoomAvatarPainter().paint(canvas, const Size(imageSize, imageSize), images);
final picture = recorder.endRecording();
final img = await picture.toImage(imageSize.ceil(), imageSize.ceil());
final byteData = await img.toByteData(format: ui.ImageByteFormat.png);
final pngBytes = byteData!.buffer.asUint8List();
final file = await File(path).create();
file.writeAsBytesSync(pngBytes);
return path;
}
static Future<ui.Image> _download(String? url) async {
if (url == null || url.isEmpty) {
return load(AppConstant.defaultAvatarImage);
}
try {
final file = await DefaultCacheManager().getSingleFile(url);
final ui.Codec codec = await ui.instantiateImageCodec(file.readAsBytesSync());
final ui.FrameInfo fi = await codec.getNextFrame();
return fi.image;
} catch (e) {
return load(AppConstant.defaultAvatarImage);
}
}
/// 通过assets路径,获取资源图片
static Future<ui.Image> load(String asset) async {
final ByteData data = await rootBundle.load(asset);
final ui.Codec codec = await ui.instantiateImageCodec(data.buffer.asUint8List());
final ui.FrameInfo fi = await codec.getNextFrame();
return fi.image;
}
AvatarImageUtil._();
}
class RoomAvatarPainter {
final Paint _paint = Paint()
..color = const Color(0xFFE6E6E6) // 画笔颜色
..strokeCap = StrokeCap.round //画笔笔触类型
..isAntiAlias = true //是否启动抗锯齿
..strokeWidth = 6.0 //画笔的宽度
..style = PaintingStyle.fill; // 样式
paint(Canvas canvas, Size size, List<ui.Image> images) {
Paint backgroundPaint = Paint()..color = const Color(0xFFFFFFFF);
canvas.drawRect(Rect.fromLTWH(0, 0, size.width, size.height), backgroundPaint);
final int count = images.length;
//头像的布局规则
List<List<int>> layoutRules = [
[1], // 1
[2], // 2
[1, 2], // 3
[2, 2], // 4
[2, 3], // 5
[3, 3], // 6
[1, 3, 3], // 7
[2, 3, 3], // 8
[3, 3, 3], // 9
];
final rule = layoutRules[count - 1];
final double imageSize = size.width / 3;
final double totalHeight = imageSize * rule.length;
final double startY = (size.height - totalHeight) / 2;
int imageIndex = 0;
for (int i = 0; i < rule.length; i++) {
final rowCount = rule[i];
final rowY = startY + i * imageSize;
final rowX = (size.width - rowCount * imageSize) / 2;
for (int j = 0; j < rowCount; j++) {
final image = images[imageIndex++];
final srcRect = Rect.fromLTWH(0, 0, image.width.toDouble(), image.height.toDouble());
final dstRect = Rect.fromLTWH(rowX + j * imageSize, rowY, imageSize, imageSize);
canvas.save();
canvas.clipPath(Path()..addOval(dstRect));
canvas.drawImageRect(image, srcRect, dstRect, _paint);
canvas.restore();
}
}
}
}
总结
这就是Flutter 实现仿微信群头像排列相关代码,希望能帮助到你!