How to customize google maps marker icon in Flutter
16,891
Solution 1
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.
Solution 2
- uses image package, https://pub.dev/packages/image, as im
- download image File 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;
}
Author by
Admin
Updated on June 05, 2022Comments
-
Admin almost 2 years
I am using google_maps_flutter in my flutter app to use google map I have custom marker icon and I load this with BitmapDescriptor.fromBytes(markerIcon) But I want to show icon from Url with some text. here is my flutter code:
Map<MarkerId, Marker> markers = <MarkerId, Marker>{}; // CLASS MEMBER, MAP OF MARKS void _add([center]) async { for (int i = 0; i < sallersList.length; i++) { if (sallersList[i]["uID"] != currentUser.uid) { /*var request = await http.get(sallersList[i]["user_image"]); var bytes = await request.bodyBytes;*/ final Uint8List markerIcon = await getBytesFromCanvas(150, 150); var markerIdVal = sallersList[i]["uID"]; final MarkerId markerId = MarkerId(markerIdVal); // creating a new MARKER final Marker marker = Marker( markerId: markerId, position: LatLng( sallersList[i]["latitude"], //+ sin(1 * pi / 6.0) / 20.0, sallersList[i]["longitude"] //+ cos(1 * pi / 6.0) / 20.0, ), // icon: BitmapDescriptor.fromBytes(bytes.buffer.asUint8List(),), icon: BitmapDescriptor.fromBytes(markerIcon), infoWindow: InfoWindow( title: sallersList[i]["user_name"], snippet: sallersList[i]["address"]), onTap: () { // print(sallersList[i]["uID"]); Navigator.of(context).push(new MaterialPageRoute( builder: (BuildContext context) => new DirectDetails())); }, ); if (this.mounted) setState(() { // adding a new marker to map markers[markerId] = marker; }); } } } Future<Uint8List> getBytesFromCanvas(int width, int height) async { final ui.PictureRecorder pictureRecorder = ui.PictureRecorder(); final Canvas canvas = Canvas(pictureRecorder); final Paint paint = Paint()..color = Colors.blue; final Radius radius = Radius.circular(width/2); canvas.drawRRect( RRect.fromRectAndCorners( Rect.fromLTWH(0.0, 0.0, width.toDouble(), height.toDouble()), topLeft: radius, topRight: radius, bottomLeft: radius, bottomRight: radius, ), paint); TextPainter painter = TextPainter(textDirection: TextDirection.ltr); painter.text = TextSpan( text: '1', style: TextStyle(fontSize: 65.0, color: Colors.white), ); painter.layout(); painter.paint( canvas, Offset((width * 0.5) - painter.width * 0.5, (height * .5) - painter.height * 0.5)); final img = await pictureRecorder.endRecording().toImage(width, height); final data = await img.toByteData(format: ui.ImageByteFormat.png); return data.buffer.asUint8List(); }
This is what we want to achieve
This is what I am able to achieve.
Is it possible to achieve the same via flutter or any external image dependency that can create the images on the fly.
-
newbie over 4 yearswill this bogged down when we have many icons to be refreshed and drawn?
-
temirbek over 3 yearshow to add shadow to custom marker? I mean real shadow, in addition to that blue circle with opacity.
-
Anwar almost 3 yearsthank you its work for me in this case user-images.githubusercontent.com/35429445/…
-
Mr B over 2 yearshow would you overlay tag circle on top of the image? i want to achieve something like this: drive.google.com/file/d/1NM9FTPXG-wH5boMURVdZgX0jtfVPupnm/…