You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 05:30:42