Est-il possible d'utiliser des chemins SVG pour créer un marqueur avec le plugin google_maps_flutter ? Je sais que vous pouvez utiliser des fichiers .png en utilisant:
icon: BitmapDescriptor.fromAsset("images/myFile.png")
Et les chemins SVG?
Merci
3 Réponses :
vient de consulter la documentation de la classe BitmapDescriptor Vous pouvez essayer la méthode de classe fromAssetImage ()
fromAssetImage () n'accepte pas les fichiers SVG, uniquement les images bitmap.
Cela peut être réalisé en utilisant le package flutter_svg .
BitmapDescriptor bitmapDescriptor = await _bitmapDescriptorFromSvgAsset(context, 'assets/images/someimage.svg');
Marker marker = Marker(markerId: MarkerId('someId'), icon: bitmapDescriptor, position: LatLng(someLatitude, someLongitude));
Vous pouvez ensuite utiliser le BitmapDescriptor pour créer un marqueur comme d'habitude:
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());
}
Solution géniale! Une chose à prendre en compte est que les marqueurs chargés à partir d'octets sont plus lents à travailler (12x plus lentement) même une fois chargés en raison d'une optimisation manquante dans le plugin google_maps_flutter. J'ai créé un problème pour ce problème, github.com/flutter/flutter/issues/41731 n'hésitez pas à le voter;)
Voici quelques options:
getBitmapDescriptorFromSvgAsset - svg des actifs getBitmapDescriptorFromSvgString - svg sous forme de chaîne de db / remote / peu importe final icon = await BitmapDescriptorHelper.getBitmapDescriptorFromSvgAsset(
context, "assets/icons/some_svg_icon.svg");
final Marker marker = Marker(
icon: icon,
...
);
de votre classe de widget:
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());
}
}
appréciez :)