Flutter Google Map — Creating Custom Numbered Icons Like a Pro 😎

Krutik Jain
3 min readMar 25, 2024

--

Alright, let’s get straight to the point. You want your Flutter app to have those snazzy numbered map icons, because why settle for ordinary when you can make things interesting? 📍

Before diving into the artistic world of map customization, you need to add a couple of things to your pubspec.yaml. Just the usual suspects: 💀

dependencies:
flutter:
sdk: flutter
google_maps_flutter: ^2.6.0
flutter_polyline_points: ^2.0.0
location: ^5.0.3

Now, let’s talk about the API key, because clearly, Google Maps doesn’t run on hopes and dreams. Head over to the Google Cloud Console, navigate through their maze, and get that precious API key. Once you’ve secured the key to the kingdom, place it in your Android manifest like so:

<manifest>
<application>
...
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="YOUR_API_KEY_HERE"/>
...
</application>
</manifest>

Crafting the Custom Icons

First, let’s handle the base icon. It’s like giving life to your app, but without the philosophical implications:

Future<BitmapDescriptor> createCustomIcon(String assetPath, {required int width, required int height}) async {
ByteData data = await rootBundle.load(assetPath);
ui.Codec codec = await ui.instantiateImageCodec(
data.buffer.asUint8List(), targetWidth: width, targetHeight: height);
ui.FrameInfo fi = await codec.getNextFrame();
final Uint8List bytes = (await fi.image.toByteData(format: ui.ImageByteFormat.png))!.buffer.asUint8List();
return BitmapDescriptor.fromBytes(bytes);
}

Simple enough, right?

Adding Numbers

Next, let’s add some numbers to these icons because we like to keep things organized:

Future<BitmapDescriptor> createCustomIconWithNumber(String assetPath, int number, {required int width, required int height}) async {
// Load and prepare the icon for some text addition
ByteData data = await rootBundle.load(assetPath);
ui.Codec codec = await ui.instantiateImageCodec(
data.buffer.asUint8List(), targetWidth: width, targetHeight: height);
ui.FrameInfo fi = await codec.getNextFrame();
final Uint8List imageData = (await fi.image.toByteData(format: ui.ImageByteFormat.png))!.buffer.asUint8List();

// Prepare the canvas for drawing
final ui.PictureRecorder pictureRecorder = ui.PictureRecorder();
final Canvas canvas = Canvas(pictureRecorder);
final Size canvasSize = Size(width.toDouble(), height.toDouble());
final ui.Image image = await decodeImageFromList(imageData);
paintImage(canvas: canvas, image: image, rect: Rect.fromLTWH(0, 0, canvasSize.width, canvasSize.height));

// Drawing the text, because what’s an icon without some flair?
TextPainter textPainter = TextPainter(
textAlign: TextAlign.center, textDirection: TextDirection.ltr);
textPainter.text = TextSpan(
text: '$number',
style: TextStyle(fontSize: width * 0.65, color: Colors.white, fontWeight: FontWeight.bold),
);
textPainter.layout();
textPainter.paint(canvas, Offset(width / 2 - textPainter.width / 2, height / 2 - textPainter.height / 2 - 35));

// Convert that masterpiece into an image
final ui.Image markerAsImage = await pictureRecorder.endRecording().toImage(width, height);
final ByteData? byteData = await markerAsImage.toByteData(format: ui.ImageByteFormat.png);
return BitmapDescriptor.fromBytes(byteData.buffer.asUint8List());
}

Let’s Get Those Icons on the Map

Now, combine all your hard work and actually put those icons on the map:

Future<void> _calculateRoute() async {
// Some sophisticated route calculation goes here...
BitmapDescriptor icon = await createCustomIconWithNumber('assets/map_pin.png', i, width: 64, height: 128);
markers.add(Marker(
markerId: MarkerId(route[i].toString()),
position: route[i],
icon: icon,
));
// Continue with your route calculation and icon placement...
}

Conclusion

You did it! Your Flutter map now has custom numbered icons, making it as unique as your coding journey. Feel like a rock star yet? You should!🤘

If you found this guide helpful, why not give it a clap or share it?👏

For those who want to delve deeper or see the code in its full glory, check out the Full Code.🧑‍💻

--

--