This open-source library contains utilities that are useful for a wide range of applications using theGoogle Maps SDK for Android.
- Marker animation- animates a marker from one position to another
- Marker clustering— handles the display of a large number of points
- Marker icons— display text on your Markers
- Heatmaps— display a large number of points as a heat map
- Import KML— displays KML data on the map
- Import GeoJSON— displays and styles GeoJSON data on the map
- Polyline encoding and decoding— compact encoding for paths, interoperability with Maps API web services
- Spherical geometry— for example: computeDistance, computeHeading, computeArea
- Street View metadata— checks if a Street View panorama exists at a given location
You can also find Kotlin extensions for this library inMaps Android KTX.
- Android API level 21+
- AnAPI key
dependencies {
//Utilities for Maps SDK for Android (requires Google Play Services)
//You do not need to add a separate dependency for the Maps SDK for Android
//since this library builds in the compatible version of the Maps SDK.
implementation'com.google.maps.android:android-maps-utils:3.9.0'
//Optionally add the Kotlin Extensions (KTX) for full Kotlin language support
//See latest version at https://github.com/googlemaps/android-maps-ktx
//implementation 'com.google.maps.android:maps-utils-ktx:<latest-version>'
}
This repository includes asample appthat illustrates the use of this library.
To run the demo app, you'll have to:
- Get a Maps API key
- Add a file
local.properties
in the root project (this file shouldNOTbe under version control to protect your API key) - Add a single line to
local.properties
that looks likeMAPS_API_KEY=YOUR_API_KEY
,whereYOUR_API_KEY
is the API key you obtained in the first step - Build and run the
debug
variant for the Maps SDK for Android version
See thereference documentationfor a full list of classes and their methods.
Full guides for using the utilities are published in Google Maps Platform documentation.
Marker utilities
- Marker animationsource,sample code
- Marker clusteringsource,guide
- Advanced Markers clusteringsource,sample code
- Marker iconssource,sample code
Data visualization utilities
Polyline and spherical geometry utilities
- Polyline encoding and decodingsource,encoding sample,decoding sample
- Spherical geometrysource,compute distance sample
Street View metadata utility
The StreetViewUtil class provides functionality to check whether a location is supported in StreetView. You can avoid errors whenadding a Street View panoramato an Android app by calling this metadata utility and only adding a Street View panorama if the response isOK
.
StreetViewUtils.fetchStreetViewData(LatLng(8.1425918,11.5386121),BuildConfig.MAPS_API_KEY,Source.DEFAULT)
fetchStreetViewData
will returnNOT_FOUND
,OK
,ZERO_RESULTS
orREQUEST_DENIED
,depending on the response.
By default, theSource
is set toSource.DEFAULT
,but you can also specifySource.OUTDOOR
to request outdoor Street View panoramas.
Migration Guide from v0.x to 1.0
Improvements made in version1.0.0of the library to support multiple layers on the map caused breaking changes to versions prior to it. These changes also modify behaviors that are documented in theMaps SDK for Android Maps documentationsite. This section outlines all those changes and how you can migrate to use this library since version 1.0.0.
Click events originate in the layer-specific object that added the marker/ground overlay/polyline/polygon. In each layer, the click handlers are passed to the marker, ground overlay, polyline, or polygonCollection
object.
// Clustering
ClusterManager<ClusterItem>clusterManager=// Initialize ClusterManager - if you're using multiple maps features, use the constructor that passes in Manager objects (see next section)
clusterManager.setOnClusterItemClickListener(item-> {
// Listen for clicks on a cluster item here
returnfalse;
});
clusterManager.setOnClusterClickListener(item-> {
// Listen for clicks on a cluster here
returnfalse;
});
// GeoJson
GeoJsonLayergeoJsonLayer=// Initialize GeoJsonLayer - if you're using multiple maps features, use the constructor that passes in Manager objects (see next section)
geoJsonLayer.setOnFeatureClickListener(feature-> {
// Listen for clicks on GeoJson features here
});
// KML
KmlLayerkmlLayer=// Initialize KmlLayer - if you're using multiple maps features, use the constructor that passes in Manager objects (see next section)
kmlLayer.setOnFeatureClickListener(feature-> {
// Listen for clicks on KML features here
});
If you use one of Manager objects in the packagecom.google.maps.android
(e.g.GroundOverlayManager
,MarkerManager
,etc.), say from adding a KML layer, GeoJson layer, or Clustering, you will have to rely on the Collection specific to add an object to the map rather than adding that object directly toGoogleMap
.This is because each Manager sets itself as a click listener so that it can manage click events coming from multiple layers.
For example, if you have additionalGroundOverlay
objects:
New
GroundOverlayManagergroundOverlayManager=// Initialize
// Create a new collection first
GroundOverlayManager.CollectiongroundOverlayCollection=groundOverlayManager.newCollection();
// Add a new ground overlay
GroundOverlayOptionsoptions=//...
groundOverlayCollection.addGroundOverlay(options);
Old
GroundOverlayOptionsoptions=//...
googleMap.addGroundOverlay(options);
This same pattern applies forMarker
,Circle
,Polyline
,andPolygon
.
If you useMarkerManager
,adding anInfoWindowAdapter
and/or anOnInfoWindowClickListener
should be done on theMarkerManager.Collection
object.
New
CustomInfoWindowAdapteradapter=//...
OnInfoWindowClickListenerlistener=//...
// Create a new Collection from a MarkerManager
MarkerManagermarkerManager=//...
MarkerManager.Collectioncollection=markerManager.newCollection();
// Set InfoWindowAdapter and OnInfoWindowClickListener
collection.setInfoWindowAdapter(adapter);
collection.setOnInfoWindowClickListener(listener);
// Alternatively, if you are using clustering
ClusterManager<ClusterItem>clusterManager=//...
MarkerManager.CollectionmarkerCollection=clusterManager.getMarkerCollection();
markerCollection.setInfoWindowAdapter(adapter);
markerCollection.setOnInfoWindowClickListener(listener);
Old
CustomInfoWindowAdapteradapter=//...
OnInfoWindowClickListenerlistener=//...
googleMap.setInfoWindowAdapter(adapter);
googleMap.setOnInfoWindowClickListener(listener);
If you useMarkerManager
,adding anOnMarkerDragListener
should be done on theMarkerManager.Collection
object.
New
// Create a new Collection from a MarkerManager
MarkerManagermarkerManager=//...
MarkerManager.Collectioncollection=markerManager.newCollection();
// Add markers to collection
MarkerOptionsmarkerOptions=//...
collection.addMarker(markerOptions);
//...
// Set OnMarkerDragListener
GoogleMap.OnMarkerDragListenerlistener=//...
collection.setOnMarkerDragListener(listener);
// Alternatively, if you are using clustering
ClusterManager<ClusterItem>clusterManager=//...
MarkerManager.CollectionmarkerCollection=clusterManager.getMarkerCollection();
markerCollection.setOnMarkerDragListener(listener);
Old
// Add markers
MarkerOptionsmarkerOptions=//...
googleMap.addMarker(makerOptions);
// Add listener
GoogleMap.OnMarkerDragListenerlistener=//...
googleMap.setOnMarkerDragListener(listener);
A bugwas fixed in v1 to properly clear and re-add markers via theClusterManager
.
For example, this didn't work pre-v1, but works for v1 and later:
clusterManager.clearItems();
clusterManager.addItems(items);
clusterManager.cluster();
If you're using custom clustering (i.e, if you're extendingDefaultClusterRenderer
), you must override two additional methods in v1:
onClusterItemUpdated()
- should be the same* as youronBeforeClusterItemRendered()
methodonClusterUpdated()
- should be the same* as youronBeforeClusterRendered()
method
*Note that these methods can't be identical, as you need to use aMarker
instead ofMarkerOptions
See theCustomMarkerClusteringDemoActivity
in the demo app for a complete example.
New
privateclassPersonRendererextendsDefaultClusterRenderer<Person> {
...
@Override
protectedvoidonBeforeClusterItemRendered(Personperson,MarkerOptionsmarkerOptions) {
// Draw a single person - show their profile photo and set the info window to show their name
markerOptions
.icon(getItemIcon(person))
.title(person.name);
}
/**
* New in v1
*/
@Override
protectedvoidonClusterItemUpdated(Personperson,Markermarker) {
// Same implementation as onBeforeClusterItemRendered() (to update cached markers)
marker.setIcon(getItemIcon(person));
marker.setTitle(person.name);
}
@Override
protectedvoidonBeforeClusterRendered(Cluster<Person>cluster,MarkerOptionsmarkerOptions) {
// Draw multiple people.
// Note: this method runs on the UI thread. Don't spend too much time in here (like in this example).
markerOptions.icon(getClusterIcon(cluster));
}
/**
* New in v1
*/
@Override
protectedvoidonClusterUpdated(Cluster<Person>cluster,Markermarker) {
// Same implementation as onBeforeClusterRendered() (to update cached markers)
marker.setIcon(getClusterIcon(cluster));
}
...
}
Old
privateclassPersonRendererextendsDefaultClusterRenderer<Person> {
...
@Override
protectedvoidonBeforeClusterItemRendered(Personperson,MarkerOptionsmarkerOptions) {
// Draw a single person - show their profile photo and set the info window to show their name
markerOptions
.icon(getItemIcon(person))
.title(person.name);
}
@Override
protectedvoidonBeforeClusterRendered(Cluster<Person>cluster,MarkerOptionsmarkerOptions) {
// Draw multiple people.
// Note: this method runs on the UI thread. Don't spend too much time in here (like in this example).
markerOptions.icon(getClusterIcon(cluster));
}
...
}
Contributions are welcome and encouraged! See thecontributing guidefor more info.
This library is offered via an open sourcelicense.It is not governed by the Google Maps PlatformTechnical Support Services Guidelines,theSLA,or theDeprecation Policy(however, any Google Maps Platform services used by the library remain subject to the Google Maps Platform Terms of Service).
This library adheres tosemantic versioningto indicate when backwards-incompatible changes are introduced.
If you find a bug, or have a feature request, pleasefile an issueon GitHub.
If you would like to get answers to technical questions from other Google Maps Platform developers, ask through one of ourdeveloper community channelsincluding the Google Maps PlatformDiscord server.