Currently, if you need to use Google Maps on your Flutter app and want to use custom icons for your map markers, you’re limited in terms of options. You can either use an asset or a file as a marker icon and that’s it.
Recently, while working on a project here at Coletiv, I needed to fetch the images of the markers from a REST API and display them on a Google Maps map.
Since everything is a widget in Flutter, you might think it’s possible to use any widget as a marker icon, and then hook an Image widget with the marker and be done with it. But, unfortunately, that’s not possible yet. You can track that feature request in this Github issue.
If you’re willing to let Google Maps go, I recommend that you try the Flutter Map package which allows you to use any widget as a marker icon. The problem is that this package only works with Map Tile API’s which are lacking in terms of performance comparing to the native Google Maps library.
Now, let’s check how I’ve implemented this feature.
1 - First implementation using HTTP
import 'package:http/http.dart' as http; final http.Response response = await http.get(imageUrl); BitmapDescriptor.fromBytes(response.bodyBytes);
Simple enough isn’t it? We have 2 problems with this implementation though. First, you’re performing a network request for every marker every time which can delay the loading. Second, the image is not resized, so we can have markers with different sizes, which is weird.
Let’s solve these problems.
2 - Caching the marker images with Flutter Cache Manager
import 'package:flutter_cache_manager/flutter_cache_manager.dart'; final File markerImageFile = await DefaultCacheManager().getSingleFile(imageUrl); final Uint8List markerImageBytes = await markerImageFile.readAsBytes(); BitmapDescriptor.fromBytes(markerImageBytes);
The DefaultCacheManager from the Flutter Cache Manager package will handle all the caching logic for you. First, it checks the cache to see if the file was already downloaded or not, and if it was, it will check if the file is old (older than 30 days by default). If the file is recent it will be returned right away but if it needs to be refreshed or doesn’t exist, it will be downloaded and stored in the cache and then returned. You can customize this behavior by implementing the BaseCacheManager or by doing the caching mechanism yourself.
With this, you’ll see that the markers load much faster.
import 'dart:typed_data'; import 'dart:ui'; import 'package:flutter_cache_manager/flutter_cache_manager.dart'; final int targetWidth = 60; final File markerImageFile = await DefaultCacheManager().getSingleFile(imageUrl); final Uint8List markerImageBytes = await markerImageFile.readAsBytes(); final Codec markerImageCodec = await instantiateImageCodec( imageBytes, targetWidth: targetWidth, ); final FrameInfo frameInfo = await imageCodec.getNextFrame(); final ByteData byteData = await frameInfo.image.toByteData( format: ImageByteFormat.png, ); final Uint8List resizedMarkerImageBytes = byteData.buffer.asUint8List(); BitmapDescriptor.fromBytes(resizedMarkerImageBytes);
With this, you’re resizing the marker image to the targetWidth and converting it to PNG format which is required by the marker icon BitmapDescriptor.fromBytes method.
And that's it! Now you will have a properly resized marker with a network image icon that won’t take forever to load, showing in your Google Map widget. 👏 👏 👏
There is an example project at the Coletiv Github account that uses all this code and also implements Clusters on Google Maps, which is yet another unsupported feature that will be discussed in another article.
Be sure to check it out in the flutter google maps clusters repo, to see all the code with proper syntax highlighting and take a sneak peek at how I've implemented Clusters.
Note: You need to get your Google Maps API Key and add it here and here.
I hope this guide helps you and your team to save some time with the deployments and remember to continuously check Fastlane advancements and updates. More and more tools will come that may expedite this enduring process of deployment!
In case you don’t know, Coletiv is a software development studio from Porto specialized in Elixir, iOS, and Android app development. But we do all kinds of stuff. We take care of UX/UI design, web development, and even security for you.