How to customize google maps marker icon in Flutter
To achieve the above styling fallow steps bellow:
- Import packages
import 'dart:async';import 'dart:ui' as ui;import 'dart:typed_data';import 'dart:io';import 'package:flutter/material.dart';
- (Optional) Add a helper function to get image by the path
Future<ui.Image> getImageFromPath(String imagePath) async { File imageFile = File(imagePath); Uint8List imageBytes = imageFile.readAsBytesSync(); final Completer<ui.Image> completer = new Completer(); ui.decodeImageFromList(imageBytes, (ui.Image img) { return completer.complete(img); }); return completer.future;}
- Add function
getMarkerIcon()
returningBitmapDescriptor
. This is a replacement for your functiongetBytesFromCanvas()
Future<BitmapDescriptor> getMarkerIcon(String imagePath, Size size) async { final ui.PictureRecorder pictureRecorder = ui.PictureRecorder(); final Canvas canvas = Canvas(pictureRecorder); final Radius radius = Radius.circular(size.width / 2); final Paint tagPaint = Paint()..color = Colors.blue; final double tagWidth = 40.0; final Paint shadowPaint = Paint()..color = Colors.blue.withAlpha(100); final double shadowWidth = 15.0; final Paint borderPaint = Paint()..color = Colors.white; final double borderWidth = 3.0; final double imageOffset = shadowWidth + borderWidth; // Add shadow circle canvas.drawRRect( RRect.fromRectAndCorners( Rect.fromLTWH( 0.0, 0.0, size.width, size.height ), topLeft: radius, topRight: radius, bottomLeft: radius, bottomRight: radius, ), shadowPaint); // Add border circle canvas.drawRRect( RRect.fromRectAndCorners( Rect.fromLTWH( shadowWidth, shadowWidth, size.width - (shadowWidth * 2), size.height - (shadowWidth * 2) ), topLeft: radius, topRight: radius, bottomLeft: radius, bottomRight: radius, ), borderPaint); // Add tag circle canvas.drawRRect( RRect.fromRectAndCorners( Rect.fromLTWH( size.width - tagWidth, 0.0, tagWidth, tagWidth ), topLeft: radius, topRight: radius, bottomLeft: radius, bottomRight: radius, ), tagPaint); // Add tag text TextPainter textPainter = TextPainter(textDirection: TextDirection.ltr); textPainter.text = TextSpan( text: '1', style: TextStyle(fontSize: 20.0, color: Colors.white), ); textPainter.layout(); textPainter.paint( canvas, Offset( size.width - tagWidth / 2 - textPainter.width / 2, tagWidth / 2 - textPainter.height / 2 ) ); // Oval for the image Rect oval = Rect.fromLTWH( imageOffset, imageOffset, size.width - (imageOffset * 2), size.height - (imageOffset * 2) ); // Add path for oval image canvas.clipPath(Path() ..addOval(oval)); // Add image ui.Image image = await getImageFromPath(imagePath); // Alternatively use your own method to get the image paintImage(canvas: canvas, image: image, rect: oval, fit: BoxFit.fitWidth); // Convert canvas to image final ui.Image markerAsImage = await pictureRecorder.endRecording().toImage( size.width.toInt(), size.height.toInt() ); // Convert image to bytes final ByteData byteData = await markerAsImage.toByteData(format: ui.ImageByteFormat.png); final Uint8List uint8List = byteData.buffer.asUint8List(); return BitmapDescriptor.fromBytes(uint8List);}
- Use it like so
final Marker marker = Marker( icon: await getMarkerIcon("path/to/your/image.png", Size(150.0, 150.0)));
Note:The tag with a number is positioned 'loosely' for the demo purpose - you might need to style it differently so it would expand with the content.
- uses image package, https://pub.dev/packages/image, as im
- download imageFile f = await _downloadFile(url, "border");im.Image img = im.decodeImage(f.readAsBytesSync());
- use drawString() to write number on it
- BitmapDescriptor.fromBytes(im.encodePng(img))
static var httpClient = new HttpClient();
Future<File> _downloadFile(String url, String filename) async { var request = await httpClient.getUrl(Uri.parse(url)); var response = await request.close(); var bytes = await consolidateHttpClientResponseBytes(response); String dir = (await getApplicationDocumentsDirectory()).path; File file = new File('$dir/$filename'); await file.writeAsBytes(bytes); return file; }