Как использовать маркеры SVG в плагине google_maps_flutter Flutter?

Я хочу разместить маркеры, используя изображения .svg в качестве значков. Я использую библиотеку google_maps_flutter. Это работало с преобразованными изображениями .png, но я не нашел способа напрямую использовать файлы .svg.

Пишу сюда после прочтения этого выпуска: Использование маркеров SVG в google_maps_flutter Плагин Flutter

И пытаюсь использовать метод fromAssetImage, как описано в этой теме: Как изменить размер значка маркера Google Map во Flutter?

Я надеялся, что эта новая версия библиотеки поможет решить мою проблему.

Я попытался решить это с помощью следующего кода:

Класс MapWidget

for (Place place in widget.places) {
          place.toMarker(
            context,
            () => _onPlaceTapped(place),
          ).then(setState((){
            markerSet.add
          }));
      }

Место класса

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. Пожалуйста, проверьте мой ответ на вопрос, который вы связали: stackoverflow.com/a/57609840/2344535

rednuht 22.08.2019 15:02

Возможный дубликат Использование маркеров SVG в google_maps_flutter Плагин Flutter

rednuht 22.08.2019 15:03

Действительно, мы говорим об одном и том же. Я попробовал то, что было рекомендовано в этом посте, но это не сработало для меня. Поэтому я подумал, что могу создать пост, показывающий код, который я пробовал. В таком случае мне закрывать тему? Я вижу, что есть новые ответы, так что я мог бы найти там свое решение сейчас.

wenolOaR 23.08.2019 17:33

Вы пробовали использовать flutter_svg? Я полагаю, что ответ с использованием этого пакета еще не был опубликован на момент создания вашего вопроса.

rednuht 23.08.2019 18:43

Да, это не так. Я имел в виду свою ситуацию в то время. Я попробую ваше решение, как только смогу.

wenolOaR 26.08.2019 10:13

Большое спасибо @rednuht! Это сработало как шарм. Поскольку я еще не могу прокомментировать ваш ответ (<50 повторений), я скажу вам здесь переименовать drawableRoot как svgDrawableRoot и, возможно, добавить комментарий о том, что размеры, используемые в picture.toPicture(32, 32), должны быть тщательно выбраны, иначе победит изображение svg. не отображаться целиком.

wenolOaR 05.09.2019 11:43

У вас есть идея, как масштабировать полученное изображение вверх и вниз? Мои маркеры слишком малы, когда я использую изображение svg.

wenolOaR 05.09.2019 12:11

Я также обнаружил, что масштабирование сложно. DrawableRoot.toPicture() принимает аргумент размера, который вы можете установить в дополнение к параметрам размера в picture.toImage(). Кажется, ни один из них не принимает во внимание соотношение пикселей устройства. Поэтому вам нужно получить соотношение пикселей из MediaQuery и умножить его на желаемый размер. Я обновил ответ, чтобы отразить это.

rednuht 05.09.2019 14:49
Создание фильтров для вашего сайта
Создание фильтров для вашего сайта
Фильтры - удобный инструмент в арсенале веб-дизайнера. Они позволяют изменять элементы на странице с помощью всего нескольких строк кода. Эти...
Анимация SVG-узоров без единой строки CSS
Анимация SVG-узоров без единой строки CSS
Недавно я работал над веб-проектом, который позволил мне поэкспериментировать с шаблонами SVG. С SVG очень приятно работать, как только вы получите...
Как использовать d3.js для рисования 2D SVG-элементов в приложении Angular?
Как использовать d3.js для рисования 2D SVG-элементов в приложении Angular?
D3.js - это обширная библиотека, используемая для привязки произвольных данных к объектной модели документа (DOM). Мы разберем основные варианты...
8
8
3 727
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Ответ на этот вопрос вы можете найти здесь:

Использование маркеров SVG в google_maps_flutter Плагин Flutter

Я попробовал ответ Реднухта, и это сработало как шарм.

РЕДАКТИРОВАТЬ (резюме)

Ответ требует использования плагина 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');
  }

основной дротик

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

Так что все, что мне нужно было сделать после этого, это правильно вызвать его, когда это необходимо.

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

Пожалуйста, кратко опишите содержание, так как ссылка может быть устаревшей.

Circle Hsiao 05.09.2019 12:10

У меня была та же проблема, и я закончил с этой реализацией из-за того, что без de devicePixelRatio он показывал пиксельные маркеры.

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);
  }

Другие вопросы по теме