#svg #dart #flutter
#svg #dart #flutter
Вопрос:
Можно ли использовать SVG-пути для создания маркера с помощью плагина google_maps_flutter? Я знаю, что вы можете использовать .png
файлы, используя:
icon: BitmapDescriptor.fromAsset("images/myFile.png")
Как насчет SVG-путей?
Спасибо
Ответ №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));
Комментарии:
1. Потрясающее решение! Следует учитывать, что маркеры, загруженные из байтов, работают намного медленнее (в 12 раз медленнее) даже после загрузки из-за отсутствия оптимизации в плагине google_maps_flutter. Я создал проблему для этой проблемы, github.com/flutter/flutter/issues/41731 не стесняйтесь голосовать за это 😉
Ответ №2:
Вот несколько вариантов:
getBitmapDescriptorFromSvgAsset
— svg из ресурсовgetBitmapDescriptorFromSvgString
— svg как строка из базы данных / удаленного / чего угодно
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,
...
);
наслаждайтесь 🙂
Комментарии:
1. ошибка: неопределенное имя «пользовательский интерфейс». (неопределенный идентификатор… и отсутствует отказ от ответственности стороннего участника?
2. Не забудьте необходимый импорт для этого кода => импортировать ‘package:google_maps_flutter / google_maps_flutter.dart’; импортировать ‘package:flutter/material.dart’; импортировать ‘dart: ui’ как пользовательский интерфейс; импортировать ‘dart: async’; импортировать ‘package: flutter_svg / flutter_svg.dart’;
Ответ №3:
только что проверил документы для класса BitmapDescriptor, вы можете попробовать метод класса fromAssetImage()
Комментарии:
1. fromAssetImage() не принимает SVG-файлы, только растровые изображения.
2. и ссылка не работает
3. Недопустимая ссылка. 404 Не найдено