flutter自定义地图Marker完美展示图片

世人都说雪景美

寒风冻脚无人疼

只道是一身正气

结论

参考Flutter集成高德地图并添加自定义Maker先实现自定义Marker。如果自定义Marker中用到了图片,那么会碰到图片没有被绘制到Marker的问题,此时需要通过precacheImage来预加载图片,从而解决此问题。

一、 背景

在高德地图上需要展示每一辆单车的电量。而amap_flutter_map确没有提供自定义Marker的方法,只有一个static BitmapDescriptor *fromBytes*(Uint8List byteData). 所以需要将定制的Widget转为图片,然后图片转为字节流,来实现自定义Marker

二、 自定义Marker

1. 定义widget

创建业务需求的widget,如下:

dart 复制代码
static Future<Widget> _createMarkerView(BuildContext context, String name,String imageName,
      {bool selected = false, MarkerTitleType markerTitleType = MarkerTitleType.small}) async {
    var height = markerTitleType.height;
    if (selected) {
      height *= 2;
    }
    var width = markerTitleType.width;

    return Container(
      height: height,
      constraints: BoxConstraints(minWidth: width),
      alignment: Alignment.center,
      decoration: BoxDecoration(
        image: DecorationImage(image: AssetImage(imageName)),
      ),
      child: Directionality(
        textDirection: TextDirection.ltr,
        child: Text(
          name,
          style: TextStyle(fontSize: selected ? 22 : 14, color: Colors.white),
          maxLines: 1,
          overflow: TextOverflow.ellipsis,
          textAlign: TextAlign.center,
        ),
      ),
    );
  }

很简单的一个背景图片和一个标题。其中这个图片,因为是从Images资源中加载,会偶现加载失败的问题。

2. widgetByteData

不展示widget到窗口,直接将widget保存为图片。代码如下:

dart 复制代码
  static Future<ByteData?> widgetToByteData(Widget widget, String imageName,
      {Alignment alignment = Alignment.center,
      Size size = const Size(double.maxFinite, double.maxFinite),
      double devicePixelRatio = 1.0,
      double pixelRatio = 1.0,
      required BuildContext context}) async {
    RenderRepaintBoundary repaintBoundary = RenderRepaintBoundary();
    RenderView renderView = RenderView(
      child: RenderPositionedBox(alignment: alignment, child: repaintBoundary),
      configuration: ViewConfiguration(
        size: size,
        devicePixelRatio: devicePixelRatio,
      ),
      view: View.of(context),
    );

    PipelineOwner pipelineOwner = PipelineOwner();
    pipelineOwner.rootNode = renderView;
    renderView.prepareInitialFrame();

    BuildOwner buildOwner = BuildOwner(focusManager: FocusManager());
    RenderObjectToWidgetElement rootElement = RenderObjectToWidgetAdapter(
      container: repaintBoundary,
      child: widget,
    ).attachToRenderTree(buildOwner);
    await precacheImage(AssetImage(imageName), rootElement);
    buildOwner.buildScope(rootElement);
    buildOwner.finalizeTree();

    pipelineOwner.flushLayout();
    pipelineOwner.flushCompositingBits();
    pipelineOwner.flushPaint();

    ui.Image image = await repaintBoundary.toImage(pixelRatio: pixelRatio);
    ByteData? byteData = await image.toByteData(format: ui.ImageByteFormat.png);

    return byteData;
  }

其中的 await precacheImage(AssetImage(imageName), rootElement); 是解决图片偶现加载失败的关键。

3. 返回BitmapDescriptor

创建Marker的时候需要一个BitmapDescriptor,代码如下:

dart 复制代码
var data = await MapConverting.widgetToByteData(view, imageName,
        context: context,
        devicePixelRatio: AMapUtil.devicePixelRatio,
        pixelRatio: AMapUtil.devicePixelRatio,
        size: Size(selected ? width * 1.5 : width, selected ? height * 1.2 : height));
    var uInt8List = data?.buffer.asUint8List();
    if (null != uInt8List) {
      bitmapDescriptor = BitmapDescriptor.fromBytes(uInt8List);

      _createdBitmapDescriptor[key] = bitmapDescriptor;
    } else {
      bitmapDescriptor = await BitmapDescriptor.fromAssetImage(imageConfiguration, MyImages.imagesIcParkingNormal);
    }

    return bitmapDescriptor;

为了方便BitmapDescriptor的管理,可以创建一个BitmapDescriptorFactory类,添加一个static final Map<String, BitmapDescriptor> *_createdBitmapDescriptor* = {};将创建过的自定义BitmapDescriptorFactory做一个全局缓存,来解决重复创建的问题。

三、precacheImage使用注意

precacheImage函数中有一个参数是context,理解为缓存图片仅仅是在此context中生效。

尝试过在首页,业务主页,地图页面对需要使用到的图片进行缓存,都失效了,只有在RenderObjectToWidgetElement创建自定义widget时,将precacheImage缓存,才能生效。

参考: Flutter集成高德地图并添加自定义Maker

相关推荐
晚烛3 小时前
实战前瞻:构建高可靠、低延迟的 Flutter + OpenHarmony 智慧交通出行平台
前端·javascript·flutter
ujainu小3 小时前
Flutter 权限管理实战手册:permission_handler 全平台适配与最佳实践
flutter
子榆.4 小时前
Flutter 与开源鸿蒙(OpenHarmony)工程化实践:CI/CD、性能监控与多端发布
flutter·开源·harmonyos
QuantumLeap丶4 小时前
《Flutter全栈开发实战指南:从零到高级》- 26 -持续集成与部署
android·flutter·ios
晚烛7 小时前
实战前瞻:构建高安全、强协同的 Flutter + OpenHarmony 智慧金融移动银行平台(支持国产密码体系、生物认证与信创全栈适配)
安全·flutter·金融
子榆.7 小时前
Flutter 与开源鸿蒙(OpenHarmony)国际化与无障碍适配指南:打造真正包容的跨平台应用
flutter·华为·开源·harmonyos
子榆.8 小时前
Flutter 与开源鸿蒙(OpenHarmony)深度集成:从原理到实战进阶
flutter·华为·开源·harmonyos
子榆.9 小时前
Flutter 与开源鸿蒙(OpenHarmony)的融合:跨平台开发新纪元
flutter·华为·开源·harmonyos
走在路上的菜鸟10 小时前
Android学Dart学习笔记第二十三节 类-扩展类型
android·笔记·学习·flutter
晚烛10 小时前
智启工厂脉搏:基于 OpenHarmony + Flutter 的信创工业边缘智能平台构建实践
前端·javascript·flutter