Flutter高仿微信系列共59篇,从Flutter客户端、Kotlin客户端、Web服务器、数据库表结构、Xmpp即时通讯服务器、视频通话服务器、腾讯云服务器全面讲解。
/** * 处理合并群头像 * @groupId 群id * @avatarList 头像列表 */ static processMergeAvatarImage(String groupId, ListavatarList) async { if(avatarList.isEmpty){ return; } List filePathList = []; for(int i = 0; i < avatarList.length; i++){ if(avatarList[i].isNotEmpty){ String avatarFilePath = await getCacheFilePath(CommonUtils.getReallyImage(avatarList[i])); filePathList.add(avatarFilePath); } } if(filePathList.isEmpty){ return; } //合成群头像 String groupAvatar = await mergeAvatarImage(filePathList); LogUtils.d("合并头像地址"); GroupBean? groupBean = await GroupRepository.getInstance().findGroupByGroupId(groupId); if(groupBean != null){ groupBean?.avatar = groupAvatar; GroupRepository.getInstance().updateGroup(groupBean); String serverResultAvatar = await UploadUtils.getInstance().uploadGroupAvatar(groupId, groupAvatar); //设置服务器头像地址 groupBean?.avatar = serverResultAvatar; //发送消息通知更改群头像 ChatSendBean chatSendBean = ChatSendBean(); int contentType = CommonUtils.GROUP_CHAT_TYPE_REFRESH; chatSendBean.contentType = contentType; chatSendBean.content = serverResultAvatar; int id = DateTime.now().millisecondsSinceEpoch; String toJid = "${groupId}@conference.wangning"; String msg = jsonEncode(chatSendBean); XmppManager.getInstance().sendGroupMessageWithType(toJid, msg, "${id}", id); //GroupRepository.getInstance().updateGroupServer(groupBean); LogUtils.d("合并头像更新成功 ${serverResultAvatar}"); } } /** * 合并群头像 * 不管多少个,默认取9个,生成3行3列的图片(从文件读取图片) */ static Future mergeAvatarImage(List filePathList) async { if(filePathList.isEmpty){ return ""; } filePathList = _interceptList(filePathList); const kCanvasSize = 200.0; final Random rd = Random(); final int numColors = Colors.primaries.length; final color = Colors.primaries[rd.nextInt(numColors)]; final recorder = ui.PictureRecorder(); final canvas = Canvas(recorder, Rect.fromPoints(Offset(0.0, 0.0), Offset(kCanvasSize, kCanvasSize))); final stroke = Paint() ..color = Colors.grey ..style = PaintingStyle.stroke; canvas.drawRect(Rect.fromLTWH(0.0, 0.0, kCanvasSize, kCanvasSize), stroke); final paint = Paint() ..color = color ..style = PaintingStyle.fill; //3行3列 for(int i = 0; i < 3; i++){ for(int j = 0; j < 3; j++){ String filePath = filePathList[i*3 + j]; //LogUtils.d("文件路径:${filePath}"); //加载文件图片 ui.Image fileImage = await _loadFileImage(filePath); //取图片宽高最小的值 int fileWidth = fileImage.width >= fileImage.height ? fileImage.height : fileImage.width; double scale = kCanvasSize/3/fileWidth; //显示图片真是的宽高 double imageWidth = fileWidth * scale; double left = j * imageWidth - _getSpaceY(j); double top = i * imageWidth - _getSpaceX(i); LogUtils.d("file 参数:left = ${left} , top = ${top} , imageWidth = ${imageWidth} , fileWidth = ${fileWidth}, scale = ${scale} "); //移动x double dx = j * imageWidth; //移动y double dy = i * imageWidth; canvas.save(); canvas.translate(dx, dy); canvas.scale(scale, scale); Rect src = Rect.fromLTWH(left, top , fileWidth.toDouble(), fileWidth.toDouble()); canvas.drawImageRect(fileImage, src, src, paint); canvas.restore(); } } final picture = recorder.endRecording(); final img = await picture.toImage(200, 200); final pngBytes = await img.toByteData(format: ImageByteFormat.png); String resultFilePath = await _saveMergeGroupAvatar(pngBytes); return resultFilePath; } //如果超过9个, 截取前面9个,如果少于9个,在里面随机获取补够9个 static List _interceptList(List filePathList){ List resultFilePathList = []; //最多9个 int maxSize = 9; //个数 int size = filePathList.length; if(size >= 9){ resultFilePathList = filePathList.sublist(0,9); } else { resultFilePathList = filePathList; //还要补多少个 int repairSize = maxSize - size; for(int i = 0; i < repairSize; i++){ //在现有的列表随机取 int ran = Random().nextInt(size); resultFilePathList.add(filePathList[ran]); } } return resultFilePathList; } static int _getSpaceY(int j){ //纵轴空白 int spaceY = 0; if(j == 1){ spaceY = 40; } else if(j == 2){ spaceY = 110; } return spaceY; } //横轴空白 static int _getSpaceX(int i){ //横轴空白 int spaceX = 0; if(i == 1){ spaceX = 40; } else if(i == 2){ spaceX = 110; } return spaceX; } //从手机加载图片 static Future _loadFileImage(String filePath) async { File file = File(filePath); final Completer completer = Completer(); ui.decodeImageFromList(file.readAsBytesSync(), (ui.Image img) { return completer.complete(img); }); return completer.future; } //从资源文件加载图片 static Future _loadAssetUiImage(String imageAssetPath) async { final ByteData data = await rootBundle.load(imageAssetPath); final Completer completer = Completer(); ui.decodeImageFromList(Uint8List.view(data.buffer), (ui.Image img) { return completer.complete(img); }); return completer.future; } //保存合并群头像 static Future _saveMergeGroupAvatar(ByteData? imgBytes) async { String uuid = UUID.getUUID(); String saveFilePath = await FileUtils.getBaseFile("${uuid}.png"); File file = File(saveFilePath); final pngBytes = imgBytes!.buffer.asUint8List(); await file.writeAsBytes(pngBytes); return saveFilePath; }