如何在google_maps_flutter Flutter插件中使用SVG标记?

9
我想使用 .svg 图像作为标记图标来进行标记。我正在使用 google_maps_flutter 库。使用转换成 .png 的图片可以实现,但是我找不到直接使用 .svg 文件的方法。
在阅读了这个问题之后,我在这里发布帖子:Using SVG markers in google_maps_flutter Flutter plugin 并试图使用这个线程中描述的 fromAssetImage 方法:How to change the icon size of Google Map marker in Flutter? 我希望这个库的新版本能够解决我的问题。
我尝试使用以下代码来解决它:
MapWidget 类
for (Place place in widget.places) {
          place.toMarker(
            context,
            () => _onPlaceTapped(place),
          ).then(setState((){
            markerSet.add
          }));
      }

Place类

Future<Marker> toMarker(BuildContext context, VoidCallback onTap) async {
    return Marker(
      markerId: MarkerId(id.toString()),
      position: LatLng(lat, lon),
      icon: await category.markerIcon(createLocalImageConfiguration(context)),
      onTap: onTap,
    );

分类类

Future<BitmapDescriptor> markerIcon(ImageConfiguration configuration) async {
    BitmapDescriptor b;
    switch (type) {
      case CategoryType.FirstCategory:
        b = await BitmapDescriptor.fromAssetImage(configuration, 'assets/markers/marker-first.svg');
        break;
      case CategoryType.SecondCategory:
        b = await BitmapDescriptor.fromAssetImage(configuration, 'assets/markers/marker-second.svg');
        break;
      default:
        b = await BitmapDescriptor.fromAssetImage(configuration, 'assets/markers/marker-third.svg');
        break;
    }

    return b;
  }

如果您想知道图片的路径,它已经被添加到了 pubspec.yaml 中。

我期望在地图上用自定义标记替换默认的红色 google 标记(每个自定义标记上应该有一个小图标),但是只显示了默认标记(不是 switch 语句中的默认值,我指的是 google 的默认标记)。

使用 iOS 模拟器和 google_maps_flutter 0.5.15+1 库版本没有错误信息。


BitmapDescriptor.fromAssetImage() 不支持 SVG 文件。请查看我在您链接的问题上的答案:https://dev59.com/w7Pma4cB1Zd3GeqPmzfB#57609840 - rednuht
可能是使用SVG标记在google_maps_flutter Flutter插件中的重复问题。 - rednuht
是的,那不是我的意思。我指的是当时的情况。我会尽快尝试你的解决方案。 - wenolOaR
1
非常感谢@rednuht!这个方法非常好用。由于我的声望还不到50,无法在你的回答下发表评论,我在这里告诉你将 drawableRoot 重命名为 svgDrawableRoot,并加上一条注释,说明picture.toPicture(32, 32)中使用的尺寸必须小心选择,否则 SVG 图像将无法完全显示。 - wenolOaR
你有没有想过如何调整生成的图像大小?当我使用SVG图像时,我的标记太小了。 - wenolOaR
显示剩余3条评论
2个回答

4
您可以在这里找到这个问题的答案:

如何在google_maps_flutter Flutter插件中使用SVG标记

我尝试了rednuht的答案,它非常有效。

编辑(概述)

该答案需要使用flutter_svg插件(^0.13或0.14.1似乎对我有效)。

首先,创建一个函数,它将从资产中为您提供BitmapDescriptor。请确保在pubspec文件中声明了该资产。

import 'dart:ui' as ui;
import 'package:flutter/services.dart';
import 'package:flutter_svg/flutter_svg.dart';


Future<BitmapDescriptor> _bitmapDescriptorFromSvgAsset(BuildContext context, String assetName) async {
    String svgString = await DefaultAssetBundle.of(context).loadString(assetName);
    //Draws string representation of svg to DrawableRoot
    DrawableRoot svgDrawableRoot = await svg.fromSvgString(svgString, null);
    ui.Picture picture = svgDrawableRoot.toPicture();
    ui.Image image = await picture.toImage(26, 37);
    ByteData bytes = await image.toByteData(format: ui.ImageByteFormat.png);
    return BitmapDescriptor.fromBytes(bytes.buffer.asUint8List());
}

我在应用程序开始时实例化了一个Map对象,这样我就可以使用BitmapDescriptors而不需要使用大量的async/await调用。

data_model.dart

Map<CategoryType, BitmapDescriptor> descriptors = Map<Category, BitmapDescriptor>();

Future<void> loadBitmapDescriptors(context) async {
    descriptors[CategoryType.FirstCatgory] = await _bitmapDescriptorFromSvgAsset(context, 'assets/markers/marker-first.svg');
    descriptors[CategoryType.SecondCategory] = await _bitmapDescriptorFromSvgAsset(context, 'assets/markers/marker-second.svg');
    descriptors[CategoryType.ThirdCategory] = await _bitmapDescriptorFromSvgAsset(context, 'assets/markers/marker-third.svg');
  }

main.dart

DataModel.of(context).loadBitmapDescriptors(context);

之后我所要做的就是在需要时正确调用它。

Marker marker = Marker(markerId: MarkerId(id.toString()), icon: descriptors[category], position: LatLng(lat, lon));

请简要介绍一下内容,因为链接可能已过期。 - Circle Hsiao
DataModel在这种情况下是什么?还有,在main.dart的哪里放置了这行代码DataModel.of(context).loadBitmapDescriptors(context)?谢谢,好答案。 - Dživo Jelić

2

我曾经遇到同样的问题,最终采用了这种实现方式,因为没有设备像素比,它会显示模糊的标记。

Future<BitmapDescriptor> getBitmapDescriptorFromSVGAsset(
    BuildContext context,
    String svgAssetLink, {
    Size size = const Size(30, 30),
  }) async {
    String svgString = await DefaultAssetBundle.of(context).loadString(
      svgAssetLink,
    );
    final drawableRoot = await svg.fromSvgString(
      svgString,
      'debug: $svgAssetLink',
    );
    final ratio = ui.window.devicePixelRatio.ceil();
    final width = size.width.ceil() * ratio;
    final height = size.height.ceil() * ratio;
    final picture = drawableRoot.toPicture(
      size: Size(
        width.toDouble(),
        height.toDouble(),
      ),
    );
    final image = await picture.toImage(width, height);
    final byteData = await image.toByteData(format: ui.ImageByteFormat.png);
    final uInt8List = byteData.buffer.asUint8List();
    return BitmapDescriptor.fromBytes(uInt8List);
  }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接