Flutter实现谷歌地图自定义标记:加载用户图片URL并显示用户名
Flutter 谷歌地图自定义带用户名头像标记修复方案
核心问题原因
- 绘制顺序错误:姓名标签绘制在头像之前,被后续绘制的头像图层覆盖
- 裁剪后未恢复画布状态:头像绘制前做了圆形裁剪,未调用restore恢复画布,导致后续绘制的姓名标签也被裁剪
- 姓名标签尺寸固定,未适配用户名实际长度,布局逻辑错误
- 文字绘制偏移量写死,未做居中对齐计算
- 字体大小固定,未适配不同尺寸的标记,显示比例不协调
修复后完整代码
仅需要修改getMarkerIcon函数即可,修改后代码如下:
Future<BitmapDescriptor> getMarkerIcon( String imagePath, Size size, NearbyUsers user) async { final ui.PictureRecorder pictureRecorder = ui.PictureRecorder(); final Canvas canvas = Canvas(pictureRecorder); final Radius radius = Radius.circular(size.width / 2); final Paint nameTagPaint = Paint()..color = MyTheme.primaryColor; final Paint shadowPaint = Paint() ..color = MyTheme.primaryColor.withAlpha(120); final double shadowWidth = 15.0; final Paint borderPaint = Paint()..color = Colors.white; final double borderWidth = 3.0; final double imageOffset = shadowWidth + borderWidth; // ========== 提前计算文字尺寸,动态适配姓名标签大小 ========== TextPainter textPainter = TextPainter(textDirection: TextDirection.ltr); // 按标记尺寸动态适配字体大小,150宽标记对应约20号字体,120宽对应约16号 double fontSize = size.width * 0.13; textPainter.text = TextSpan( text: '${user.fname} ${user.lname}', style: TextStyle( fontSize: fontSize, color: Colors.white, fontWeight: FontWeight.w500), ); textPainter.layout(); // 姓名标签内边距,可自行调整 double tagPaddingH = 8, tagPaddingV = 4; double tagWidth = textPainter.width + tagPaddingH * 2; double tagHeight = textPainter.height + tagPaddingV * 2; // ========== 原有头像绘制逻辑 ========== // 绘制阴影圈 canvas.drawRRect( RRect.fromRectAndCorners( Rect.fromLTWH(0.0, 0.0, size.width, size.height), topLeft: radius, topRight: radius, bottomLeft: radius, bottomRight: radius, ), shadowPaint); // 绘制白色边框圈 canvas.drawRRect( RRect.fromRectAndCorners( Rect.fromLTWH(shadowWidth, shadowWidth, size.width - (shadowWidth * 2), size.height - (shadowWidth * 2)), topLeft: radius, topRight: radius, bottomLeft: radius, bottomRight: radius, ), borderPaint); // 保存画布状态,裁剪前必须调用 canvas.save(); // 头像圆形裁剪区 Rect oval = Rect.fromLTWH(imageOffset, imageOffset, size.width - (imageOffset * 2), size.height - (imageOffset * 2)); canvas.clipPath(Path()..addOval(oval)); // 绘制用户头像 ui.Image image = await getImageFromPath(imagePath); paintImage(canvas: canvas, image: image, rect: oval, fit: BoxFit.cover); // 恢复画布状态,取消圆形裁剪 canvas.restore(); // ========== 绘制姓名标签和文字 ========== // 姓名标签位置:头像底部居中,向下偏移10px,可自行调整偏移量修改位置 double tagX = (size.width - tagWidth) / 2; double tagY = size.height - tagHeight / 2 + 10; // 绘制标签背景 canvas.drawRRect( RRect.fromRectAndRadius( Rect.fromLTWH(tagX, tagY, tagWidth, tagHeight), Radius.circular(8)), nameTagPaint); // 绘制文字,在标签内居中 textPainter.paint(canvas, Offset(tagX + tagPaddingH, tagY + tagPaddingV)); // 转换为BitmapDescriptor,画布高度增加标签+偏移高度,避免内容被截断 final ui.Image markerAsImage = await pictureRecorder .endRecording() .toImage(size.width.toInt(), (size.height + tagHeight + 10).toInt()); final ByteData byteData = await markerAsImage.toByteData(format: ui.ImageByteFormat.png); final Uint8List uint8List = byteData.buffer.asUint8List(); return BitmapDescriptor.fromBytes(uint8List); }
补充说明
- 如果需要将姓名标签放在头像顶部,只需要修改
tagY的取值即可,比如改为-tagHeight + 10 - 标签内边距、偏移量、字体大小系数都可以根据自己的设计需求调整
- 头像填充模式改为
BoxFit.cover避免用户头像拉伸变形
内容的提问来源于stack exchange,提问作者Shruti Ramnandan Sharma
相关产品推荐
相关产品推荐

