Flutter中Google Maps带顶部文本框的自定义Marker位置异常解决
Flutter Google Maps 自定义标记位置偏移问题解决
自定义标记位置偏移的核心原因是Google Maps Marker的锚点设置不一致:
- 默认标记的锚点是
(0.5, 1.0)(底部中心,即标记的底部中心点会对准地图上的坐标点) - 通过
BitmapDescriptor.fromBytes生成的自定义标记,默认锚点是(0.5, 0.5)(中心,即标记的中心点对准坐标点)
这就导致自定义标记会比预期位置向上偏移半个标记高度,和截图中的错误情况一致。
方法1:直接设置Marker的锚点(最简单)
在创建Marker时,显式指定锚点为底部中心,和默认标记保持一致:
Marker( position: yourLatLng, icon: await createCustomMarkerWithPlateRegAndIcon( iconPath: "your_icon_path", size: const Size(100, 80), plateReg: "ABC123" ), anchor: const Offset(0.5, 1.0), // 关键:设置锚点为底部中心 )
方法2:调整自定义标记的绘制逻辑(适配默认锚点)
如果不想修改Marker的锚点,可以在绘制自定义标记时,调整画布内容的位置,让标记的中心点(默认锚点)对应实际需要的坐标点:
Future<BitmapDescriptor> createCustomMarkerWithPlateRegAndIcon({required String iconPath, required Size size, required String plateReg}) async { // 原有的TextSpan、TextPainter逻辑保持不变 TextSpan span = TextSpan( style: const TextStyle( height: 1.2, color: Colors.black, fontSize: 30.0, fontWeight: FontWeight.bold, ), text: plateReg); TextPainter tp = TextPainter( text: span, textAlign: TextAlign.center, textDirection: TextDirection.ltr, ); tp.layout(); ui.PictureRecorder recorder = ui.PictureRecorder(); Canvas canvas = Canvas(recorder); // 计算整个标记的总高度 double totalHeight = 50 + 5 + size.height; // 平移画布,让标记底部中心对齐画布中心(默认锚点位置) double translateY = (totalHeight / 2) - size.height; canvas.translate(0, translateY); // 原有的绘制黄色背景、文字、车辆图标的逻辑保持不变 Paint textBgBoxPaint = Paint() ..color = const Color.fromARGB(255, 240, 200, 50); Rect rect = Rect.fromLTWH(0, 0, tp.width + 30, 50); canvas.drawRRect( RRect.fromRectAndRadius(rect, const Radius.circular(20.0)), textBgBoxPaint, ); tp.paint(canvas, const Offset(15.0, 5.0)); Rect rectForImage = Rect.fromLTWH( 0, 55, size.width, size.height, ); canvas.clipPath(Path()..addRect(rectForImage)); ui.Image image = await getImageFromPath(iconPath, size); paintImage( canvas: canvas, image: image, rect: rectForImage, fit: BoxFit.fitHeight); ui.Picture p = recorder.endRecording(); // 改用实际内容尺寸生成图片,避免多余空白 double canvasWidth = tp.width + 30 > size.width ? tp.width + 30 : size.width; ByteData? pngBytes = await (await p.toImage( canvasWidth.toInt(), totalHeight.toInt(), )) .toByteData(format: ui.ImageByteFormat.png); ByteData emptyData = Uint8List(0).buffer.asByteData(); Uint8List data = Uint8List.view((pngBytes ?? emptyData).buffer); return BitmapDescriptor.fromBytes(data); }
额外优化建议
代码中原本固定使用160x160尺寸生成图片,会导致标记出现多余空白,建议改为使用实际内容的尺寸(如上述代码中的canvasWidth和totalHeight),这样标记边界更贴合内容,锚点定位也更准确。
内容的提问来源于stack exchange,提问作者Florentin Lupascu
相关产品推荐
相关产品推荐

