【问题标题】:Using SVG markers in google_maps_flutter Flutter plugin在 google_maps_flutter Flutter 插件中使用 SVG 标记
【发布时间】:2019-04-12 16:01:06
【问题描述】:

是否可以使用 SVG 路径通过 google_maps_flutter 插件创建标记?我知道您可以通过以下方式使用.png 文件:

icon: BitmapDescriptor.fromAsset("images/myFile.png")

SVG 路径怎么样?

谢谢

【问题讨论】:

    标签: svg dart flutter


    【解决方案1】:

    这可以使用flutter_svg 包来实现。

    import 'dart:ui' as ui; // imported as ui to prevent conflict between ui.Image and the Image widget
    import 'package:flutter/services.dart';
    import 'package:flutter_svg/flutter_svg.dart';
    import 'package:google_maps_flutter/google_maps_flutter.dart';
    
    Future<BitmapDescriptor> _bitmapDescriptorFromSvgAsset(BuildContext context, String assetName) async {
        // Read SVG file as String
        String svgString = await DefaultAssetBundle.of(context).loadString(assetName);
        // Create DrawableRoot from SVG String
        DrawableRoot svgDrawableRoot = await svg.fromSvgString(svgString, null);
    
        // toPicture() and toImage() don't seem to be pixel ratio aware, so we calculate the actual sizes here
        MediaQueryData queryData = MediaQuery.of(context);
        double devicePixelRatio = queryData.devicePixelRatio;
        double width = 32 * devicePixelRatio; // where 32 is your SVG's original width
        double height = 32 * devicePixelRatio; // same thing
    
        // Convert to ui.Picture
        ui.Picture picture = svgDrawableRoot.toPicture(size: Size(width, height));
    
        // Convert to ui.Image. toImage() takes width and height as parameters
        // you need to find the best size to suit your needs and take into account the
        // screen DPI
        ui.Image image = await picture.toImage(width, height);
        ByteData bytes = await image.toByteData(format: ui.ImageByteFormat.png);
        return BitmapDescriptor.fromBytes(bytes.buffer.asUint8List());
    }
    

    然后您可以像往常一样使用 BitmapDescriptor 创建标记:

    BitmapDescriptor bitmapDescriptor = await _bitmapDescriptorFromSvgAsset(context, 'assets/images/someimage.svg');
    Marker marker = Marker(markerId: MarkerId('someId'), icon: bitmapDescriptor, position: LatLng(someLatitude, someLongitude));
    

    【讨论】:

    • 很棒的解决方案!需要考虑的一件事是,由于 google_maps_flutter 插件中缺少优化,即使一旦加载,从字节加载的标记的使用速度也会慢得多(慢 12 倍)。我为这个问题创建了一个问题,github.com/flutter/flutter/issues/41731 随时支持它;)
    【解决方案2】:

    这里有几个选项:

    • getBitmapDescriptorFromSvgAsset - 来自资产的 svg
    • getBitmapDescriptorFromSvgString - svg 作为来自 db/remote/whatever 的字符串
    class BitmapDescriptorHelper{
      static Future<BitmapDescriptor> getBitmapDescriptorFromSvgAsset(
          BuildContext context, String svgAssetLink) async {
        final svgImage = await _getSvgImageFromAssets(context, svgAssetLink);
        final sizedSvgImage = await _getSizedSvgImage(svgImage);
    
        final pngSizedBytes = await sizedSvgImage.toByteData(format: ui.ImageByteFormat.png);
        final unit8List = pngSizedBytes.buffer.asUint8List();
        return BitmapDescriptor.fromBytes(unit8List);
      }
    
      static Future<BitmapDescriptor> getBitmapDescriptorFromSvgString(String svgString) async {
        final svgImage = await _getSvgImageFromString(svgString);
        final sizedSvgImage = await _getSizedSvgImage(svgImage);
    
        final pngSizedBytes = await sizedSvgImage.toByteData(format: ui.ImageByteFormat.png);
        final unit8List = pngSizedBytes.buffer.asUint8List();
        return BitmapDescriptor.fromBytes(unit8List);
      }
    
      static Future<ui.Image> _getSvgImageFromAssets(BuildContext context, String svgAssertLink) async {
        String svgString = await DefaultAssetBundle.of(context).loadString(svgAssertLink);
        DrawableRoot drawableRoot = svg.fromSvgString(svgString, null);
        ui.Picture picture = drawableRoot.toPicture();
        ui.Image image = await picture.toImage(
            drawableRoot.viewport.width.toInt(), drawableRoot.viewport.height.toInt());
        return image;
      }
    
      static Future<ui.Image> _getSvgImageFromString(String svgString) async {
        DrawableRoot drawableRoot = svg.fromSvgString(svgString, null);
        ui.Picture picture = drawableRoot.toPicture();
        ui.Image image = await picture.toImage(
            drawableRoot.viewport.width.toInt(), drawableRoot.viewport.height.toInt());
        return image;
      }
    
      static Future<ui.Image> _getSizedSvgImage(ui.Image svgImage) async {
        final size = 50 * ui.window.devicePixelRatio;
        final width = size;
        final height = width;
    
        final ui.PictureRecorder pictureRecorder = ui.PictureRecorder();
        final Canvas canvas = Canvas(pictureRecorder);
        final Rect svgRect =
            Rect.fromLTRB(0.0, 0.0, svgImage.width.toDouble(), svgImage.height.toDouble());
        final Rect sizedRect = Rect.fromLTRB(0.0, 0.0, width, height); // owr size here
        canvas.drawImageRect(svgImage, svgRect, sizedRect, Paint());
        return await pictureRecorder.endRecording().toImage(width.toInt(), height.toInt());
      }
    }
    

    来自您的小部件类:

          final icon = await BitmapDescriptorHelper.getBitmapDescriptorFromSvgAsset(
                                          context, "assets/icons/some_svg_icon.svg");
    
          final Marker marker = Marker(
            icon: icon,
            ...
          );
    

    享受:)

    【讨论】:

    • 错误:未定义的名称 'ui'。 (undefined_identifier ... 以及缺少第 3 方软件包免责声明?
    • 不要忘记此代码的必要导入 => import 'package:google_maps_flutter/google_maps_flutter.dart';导入“包:颤振/material.dart”;导入 'dart:ui' 作为 ui;导入“飞镖:异步”;导入'包:flutter_svg/flutter_svg.dart';
    【解决方案3】:

    刚刚查看了 BitmapDescriptor 类的文档 可以试试 fromAssetImage() 类方法

    https://pub.dev/documentation/google_maps_flutter/latest/google_maps_flutter/BitmapDescriptor/fromAssetImage.html

    【讨论】:

    • fromAssetImage() 不接受 SVG 文件,只接受位图图像。
    • 链接坏了
    • 链接无效。 404 未找到
    猜你喜欢
    • 2019-10-20
    • 2020-10-18
    • 2020-01-15
    • 2020-11-15
    • 2021-07-04
    • 1970-01-01
    • 2019-04-07
    • 2019-06-04
    • 2019-10-16
    相关资源
    最近更新 更多