Polylines and Polygons to Represent Routes and Areas Stay organized with collections Save and categorize content based on your preferences.
AI-generated Key Takeaways
This tutorial demonstrates integrating Google Maps into an Android app to display routes and areas using polylines and polygons.
It utilizes the Maps SDK for Android and provides code samples in both Java and Kotlin.
Functionality covered includes adding, styling, and handling click events for polylines and polygons.
The code showcases how to customize map elements like stroke patterns, colors, and camera positioning.
The tutorial provides a starting point for building interactive map features within your Android application.
This tutorial shows you how to add a Google map to your Android app, and usepolylines and polygons to represent routes and areas on a map.
Follow the tutorial to build an Android app using theMaps SDK for Android. The recommended development environment isAndroid Studio.
Get the code
Clone or download the Google Maps Android API v2 Samples repositoryfrom GitHub.
View the Java version of the activity:
//Copyright2020GoogleLLC////LicensedundertheApacheLicense,Version2.0(the"License");//youmaynotusethisfileexceptincompliancewiththeLicense.//YoumayobtainacopyoftheLicenseat////http://www.apache.org/licenses/LICENSE-2.0////Unlessrequiredbyapplicablelaworagreedtoinwriting,software//distributedundertheLicenseisdistributedonan"AS IS"BASIS,//WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied.//SeetheLicenseforthespecificlanguagegoverningpermissionsand//limitationsundertheLicense.packagecom.example.polygons;importandroid.os.Bundle;importandroid.widget.Toast;importandroidx.appcompat.app.AppCompatActivity;importcom.google.android.gms.maps.CameraUpdateFactory;importcom.google.android.gms.maps.GoogleMap;importcom.google.android.gms.maps.OnMapReadyCallback;importcom.google.android.gms.maps.SupportMapFragment;importcom.google.android.gms.maps.model.BitmapDescriptorFactory;importcom.google.android.gms.maps.model.CustomCap;importcom.google.android.gms.maps.model.Dash;importcom.google.android.gms.maps.model.Dot;importcom.google.android.gms.maps.model.Gap;importcom.google.android.gms.maps.model.JointType;importcom.google.android.gms.maps.model.LatLng;importcom.google.android.gms.maps.model.PatternItem;importcom.google.android.gms.maps.model.Polygon;importcom.google.android.gms.maps.model.PolygonOptions;importcom.google.android.gms.maps.model.Polyline;importcom.google.android.gms.maps.model.PolylineOptions;importcom.google.android.gms.maps.model.RoundCap;importjava.util.Arrays;importjava.util.List;/***AnactivitythatdisplaysaGooglemapwithpolylinestorepresentpathsorroutes,*andpolygonstorepresentareas.*/publicclassPolyActivityextendsAppCompatActivityimplementsOnMapReadyCallback,GoogleMap.OnPolylineClickListener,GoogleMap.OnPolygonClickListener{@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);//Retrievethecontentviewthatrendersthemap.setContentView(R.layout.activity_maps);//GettheSupportMapFragmentandrequestnotificationwhenthemapisreadytobeused.SupportMapFragmentmapFragment=(SupportMapFragment)getSupportFragmentManager().findFragmentById(R.id.map);mapFragment.getMapAsync(this);}/***Manipulatesthemapwhenit's available.*TheAPIinvokesthiscallbackwhenthemapisreadytobeused.*Thisiswherewecanaddmarkersorlines,addlistenersormovethecamera.*Inthistutorial,weaddpolylinesandpolygonstorepresentroutesandareasonthemap.*/@OverridepublicvoidonMapReady(GoogleMapgoogleMap){//Addpolylinestothemap.//Polylinesareusefultoshowarouteorsomeotherconnectionbetweenpoints.Polylinepolyline1=googleMap.addPolyline(newPolylineOptions().clickable(true).add(newLatLng(-35.016,143.321),newLatLng(-34.747,145.592),newLatLng(-34.364,147.891),newLatLng(-33.501,150.217),newLatLng(-32.306,149.248),newLatLng(-32.491,147.309)));//Storeadataobjectwiththepolyline,usedheretoindicateanarbitrarytype.polyline1.setTag("A");//Stylethepolyline.stylePolyline(polyline1);Polylinepolyline2=googleMap.addPolyline(newPolylineOptions().clickable(true).add(newLatLng(-29.501,119.700),newLatLng(-27.456,119.672),newLatLng(-25.971,124.187),newLatLng(-28.081,126.555),newLatLng(-28.848,124.229),newLatLng(-28.215,123.938)));polyline2.setTag("B");stylePolyline(polyline2);//Addpolygonstoindicateareasonthemap.Polygonpolygon1=googleMap.addPolygon(newPolygonOptions().clickable(true).add(newLatLng(-27.457,153.040),newLatLng(-33.852,151.211),newLatLng(-37.813,144.962),newLatLng(-34.928,138.599)));//Storeadataobjectwiththepolygon,usedheretoindicateanarbitrarytype.polygon1.setTag("alpha");//Stylethepolygon.stylePolygon(polygon1);Polygonpolygon2=googleMap.addPolygon(newPolygonOptions().clickable(true).add(newLatLng(-31.673,128.892),newLatLng(-31.952,115.857),newLatLng(-17.785,122.258),newLatLng(-12.4258,130.7932)));polygon2.setTag("beta");stylePolygon(polygon2);//Positionthemap's camera near Alice Springs in the center of Australia,//andsetthezoomfactorsomostofAustraliashowsonthescreen.googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(newLatLng(-23.684,133.903),4));//Setlistenersforclickevents.googleMap.setOnPolylineClickListener(this);googleMap.setOnPolygonClickListener(this);}privatestaticfinalintCOLOR_BLACK_ARGB=0xff000000;privatestaticfinalintPOLYLINE_STROKE_WIDTH_PX=12;/***Stylesthepolyline,basedontype.*@parampolylineThepolylineobjectthatneedsstyling.*/privatevoidstylePolyline(Polylinepolyline){Stringtype="";//Getthedataobjectstoredwiththepolyline.if(polyline.getTag()!=null){type=polyline.getTag().toString();}switch(type){//Ifnotypeisgiven,allowtheAPItousethedefault.case"A"://Useacustombitmapasthecapatthestartoftheline.polyline.setStartCap(newCustomCap(BitmapDescriptorFactory.fromResource(R.drawable.ic_arrow),10));break;case"B"://Usearoundcapatthestartoftheline.polyline.setStartCap(newRoundCap());break;}polyline.setEndCap(newRoundCap());polyline.setWidth(POLYLINE_STROKE_WIDTH_PX);polyline.setColor(COLOR_BLACK_ARGB);polyline.setJointType(JointType.ROUND);}privatestaticfinalintPATTERN_GAP_LENGTH_PX=20;privatestaticfinalPatternItemDOT=newDot();privatestaticfinalPatternItemGAP=newGap(PATTERN_GAP_LENGTH_PX);//Createastrokepatternofagapfollowedbyadot.privatestaticfinalList<PatternItem>PATTERN_POLYLINE_DOTTED=Arrays.asList(GAP,DOT);/***Listensforclicksonapolyline.*@parampolylineThepolylineobjectthattheuserhasclicked.*/@OverridepublicvoidonPolylineClick(Polylinepolyline){//Flipfromsolidstroketodottedstrokepattern.if((polyline.getPattern()==null)||(!polyline.getPattern().contains(DOT))){polyline.setPattern(PATTERN_POLYLINE_DOTTED);}else{//Thedefaultpatternisasolidstroke.polyline.setPattern(null);}Toast.makeText(this,"Route type "+polyline.getTag().toString(),Toast.LENGTH_SHORT).show();}/***Listensforclicksonapolygon.*@parampolygonThepolygonobjectthattheuserhasclicked.*/@OverridepublicvoidonPolygonClick(Polygonpolygon){//Flipthevaluesofthered,green,andbluecomponentsofthepolygon's color.intcolor=polygon.getStrokeColor()^0x00ffffff;polygon.setStrokeColor(color);color=polygon.getFillColor()^0x00ffffff;polygon.setFillColor(color);Toast.makeText(this,"Area type "+polygon.getTag().toString(),Toast.LENGTH_SHORT).show();}privatestaticfinalintCOLOR_WHITE_ARGB=0xffffffff;privatestaticfinalintCOLOR_DARK_GREEN_ARGB=0xff388E3C;privatestaticfinalintCOLOR_LIGHT_GREEN_ARGB=0xff81C784;privatestaticfinalintCOLOR_DARK_ORANGE_ARGB=0xffF57F17;privatestaticfinalintCOLOR_LIGHT_ORANGE_ARGB=0xffF9A825;privatestaticfinalintPOLYGON_STROKE_WIDTH_PX=8;privatestaticfinalintPATTERN_DASH_LENGTH_PX=20;privatestaticfinalPatternItemDASH=newDash(PATTERN_DASH_LENGTH_PX);//Createastrokepatternofagapfollowedbyadash.privatestaticfinalList<PatternItem>PATTERN_POLYGON_ALPHA=Arrays.asList(GAP,DASH);//Createastrokepatternofadotfollowedbyagap,adash,andanothergap.privatestaticfinalList<PatternItem>PATTERN_POLYGON_BETA=Arrays.asList(DOT,GAP,DASH,GAP);/***Stylesthepolygon,basedontype.*@parampolygonThepolygonobjectthatneedsstyling.*/privatevoidstylePolygon(Polygonpolygon){Stringtype="";//Getthedataobjectstoredwiththepolygon.if(polygon.getTag()!=null){type=polygon.getTag().toString();}List<PatternItem>pattern=null;intstrokeColor=COLOR_BLACK_ARGB;intfillColor=COLOR_WHITE_ARGB;switch(type){//Ifnotypeisgiven,allowtheAPItousethedefault.case"alpha"://Applyastrokepatterntorenderadashedline,anddefinecolors.pattern=PATTERN_POLYGON_ALPHA;strokeColor=COLOR_DARK_GREEN_ARGB;fillColor=COLOR_LIGHT_GREEN_ARGB;break;case"beta"://Applyastrokepatterntorenderalineofdotsanddashes,anddefinecolors.pattern=PATTERN_POLYGON_BETA;strokeColor=COLOR_DARK_ORANGE_ARGB;fillColor=COLOR_LIGHT_ORANGE_ARGB;break;}polygon.setStrokePattern(pattern);polygon.setStrokeWidth(POLYGON_STROKE_WIDTH_PX);polygon.setStrokeColor(strokeColor);polygon.setFillColor(fillColor);}}
View the Kotlin version of the activity:
//Copyright2020GoogleLLC////LicensedundertheApacheLicense,Version2.0(the"License");//youmaynotusethisfileexceptincompliancewiththeLicense.//YoumayobtainacopyoftheLicenseat////http://www.apache.org/licenses/LICENSE-2.0////Unlessrequiredbyapplicablelaworagreedtoinwriting,software//distributedundertheLicenseisdistributedonan"AS IS"BASIS,//WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied.//SeetheLicenseforthespecificlanguagegoverningpermissionsand//limitationsundertheLicense.packagecom.example.polygonsimportandroid.os.Bundleimportandroid.widget.Toastimportandroidx.appcompat.app.AppCompatActivityimportcom.google.android.gms.maps.CameraUpdateFactoryimportcom.google.android.gms.maps.GoogleMapimportcom.google.android.gms.maps.GoogleMap.OnPolygonClickListenerimportcom.google.android.gms.maps.GoogleMap.OnPolylineClickListenerimportcom.google.android.gms.maps.OnMapReadyCallbackimportcom.google.android.gms.maps.SupportMapFragmentimportcom.google.android.gms.maps.model.BitmapDescriptorFactoryimportcom.google.android.gms.maps.model.CustomCapimportcom.google.android.gms.maps.model.Dashimportcom.google.android.gms.maps.model.Dotimportcom.google.android.gms.maps.model.Gapimportcom.google.android.gms.maps.model.JointTypeimportcom.google.android.gms.maps.model.LatLngimportcom.google.android.gms.maps.model.PatternItemimportcom.google.android.gms.maps.model.Polygonimportcom.google.android.gms.maps.model.PolygonOptionsimportcom.google.android.gms.maps.model.Polylineimportcom.google.android.gms.maps.model.PolylineOptionsimportcom.google.android.gms.maps.model.RoundCap/***AnactivitythatdisplaysaGooglemapwithpolylinestorepresentpathsorroutes,*andpolygonstorepresentareas.*/classPolyActivity:AppCompatActivity(),OnMapReadyCallback,OnPolylineClickListener,OnPolygonClickListener{overridefunonCreate(savedInstanceState:Bundle?){super.onCreate(savedInstanceState)//Retrievethecontentviewthatrendersthemap.setContentView(R.layout.activity_maps)//GettheSupportMapFragmentandrequestnotificationwhenthemapisreadytobeused.valmapFragment=supportFragmentManager.findFragmentById(R.id.map)asSupportMapFragment?mapFragment?.getMapAsync(this)}/***Manipulatesthemapwhenit's available.*TheAPIinvokesthiscallbackwhenthemapisreadytobeused.*Thisiswherewecanaddmarkersorlines,addlistenersormovethecamera.*Inthistutorial,weaddpolylinesandpolygonstorepresentroutesandareasonthemap.*/overridefunonMapReady(googleMap:GoogleMap){//Addpolylinestothemap.//Polylinesareusefultoshowarouteorsomeotherconnectionbetweenpoints.valpolyline1=googleMap.addPolyline(PolylineOptions().clickable(true).add(LatLng(-35.016,143.321),LatLng(-34.747,145.592),LatLng(-34.364,147.891),LatLng(-33.501,150.217),LatLng(-32.306,149.248),LatLng(-32.491,147.309)))//Storeadataobjectwiththepolyline,usedheretoindicateanarbitrarytype.polyline1.tag="A"//Stylethepolyline.stylePolyline(polyline1)valpolyline2=googleMap.addPolyline(PolylineOptions().clickable(true).add(LatLng(-29.501,119.700),LatLng(-27.456,119.672),LatLng(-25.971,124.187),LatLng(-28.081,126.555),LatLng(-28.848,124.229),LatLng(-28.215,123.938)))polyline2.tag="B"stylePolyline(polyline2)//Addpolygonstoindicateareasonthemap.valpolygon1=googleMap.addPolygon(PolygonOptions().clickable(true).add(LatLng(-27.457,153.040),LatLng(-33.852,151.211),LatLng(-37.813,144.962),LatLng(-34.928,138.599)))//Storeadataobjectwiththepolygon,usedheretoindicateanarbitrarytype.polygon1.tag="alpha"//Stylethepolygon.stylePolygon(polygon1)valpolygon2=googleMap.addPolygon(PolygonOptions().clickable(true).add(LatLng(-31.673,128.892),LatLng(-31.952,115.857),LatLng(-17.785,122.258),LatLng(-12.4258,130.7932)))polygon2.tag="beta"stylePolygon(polygon2)//Positionthemap's camera near Alice Springs in the center of Australia,//andsetthezoomfactorsomostofAustraliashowsonthescreen.googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(-23.684,133.903),4f))//Setlistenersforclickevents.googleMap.setOnPolylineClickListener(this)googleMap.setOnPolygonClickListener(this)}privatevalCOLOR_BLACK_ARGB=-0x1000000privatevalPOLYLINE_STROKE_WIDTH_PX=12/***Stylesthepolyline,basedontype.*@parampolylineThepolylineobjectthatneedsstyling.*/privatefunstylePolyline(polyline:Polyline){//Getthedataobjectstoredwiththepolyline.valtype=polyline.tag?.toString()?:""when(type){"A"->{//Useacustombitmapasthecapatthestartoftheline.polyline.startCap=CustomCap(BitmapDescriptorFactory.fromResource(R.drawable.ic_arrow),10f)}"B"->{//Usearoundcapatthestartoftheline.polyline.startCap=RoundCap()}}polyline.endCap=RoundCap()polyline.width=POLYLINE_STROKE_WIDTH_PX.toFloat()polyline.color=COLOR_BLACK_ARGBpolyline.jointType=JointType.ROUND}privatevalPATTERN_GAP_LENGTH_PX=20privatevalDOT:PatternItem=Dot()privatevalGAP:PatternItem=Gap(PATTERN_GAP_LENGTH_PX.toFloat())//Createastrokepatternofagapfollowedbyadot.privatevalPATTERN_POLYLINE_DOTTED=listOf(GAP,DOT)/***Listensforclicksonapolyline.*@parampolylineThepolylineobjectthattheuserhasclicked.*/overridefunonPolylineClick(polyline:Polyline){//Flipfromsolidstroketodottedstrokepattern.if(polyline.pattern==null||!polyline.pattern!!.contains(DOT)){polyline.pattern=PATTERN_POLYLINE_DOTTED}else{//Thedefaultpatternisasolidstroke.polyline.pattern=null}Toast.makeText(this,"Route type "+polyline.tag.toString(),Toast.LENGTH_SHORT).show()}/***Listensforclicksonapolygon.*@parampolygonThepolygonobjectthattheuserhasclicked.*/overridefunonPolygonClick(polygon:Polygon){//Flipthevaluesofthered,green,andbluecomponentsofthepolygon's color.varcolor=polygon.strokeColorxor0x00ffffffpolygon.strokeColor=colorcolor=polygon.fillColorxor0x00ffffffpolygon.fillColor=colorToast.makeText(this,"Area type ${polygon.tag?.toString()}",Toast.LENGTH_SHORT).show()}privatevalCOLOR_WHITE_ARGB=-0x1privatevalCOLOR_DARK_GREEN_ARGB=-0xc771c4privatevalCOLOR_LIGHT_GREEN_ARGB=-0x7e387cprivatevalCOLOR_DARK_ORANGE_ARGB=-0xa80e9privatevalCOLOR_LIGHT_ORANGE_ARGB=-0x657dbprivatevalPOLYGON_STROKE_WIDTH_PX=8privatevalPATTERN_DASH_LENGTH_PX=20privatevalDASH:PatternItem=Dash(PATTERN_DASH_LENGTH_PX.toFloat())//Createastrokepatternofagapfollowedbyadash.privatevalPATTERN_POLYGON_ALPHA=listOf(GAP,DASH)//Createastrokepatternofadotfollowedbyagap,adash,andanothergap.privatevalPATTERN_POLYGON_BETA=listOf(DOT,GAP,DASH,GAP)/***Stylesthepolygon,basedontype.*@parampolygonThepolygonobjectthatneedsstyling.*/privatefunstylePolygon(polygon:Polygon){//Getthedataobjectstoredwiththepolygon.valtype=polygon.tag?.toString()?:""varpattern:List<PatternItem>?=nullvarstrokeColor=COLOR_BLACK_ARGBvarfillColor=COLOR_WHITE_ARGBwhen(type){"alpha"->{//Applyastrokepatterntorenderadashedline,anddefinecolors.pattern=PATTERN_POLYGON_ALPHAstrokeColor=COLOR_DARK_GREEN_ARGBfillColor=COLOR_LIGHT_GREEN_ARGB}"beta"->{//Applyastrokepatterntorenderalineofdotsanddashes,anddefinecolors.pattern=PATTERN_POLYGON_BETAstrokeColor=COLOR_DARK_ORANGE_ARGBfillColor=COLOR_LIGHT_ORANGE_ARGB}}polygon.strokePattern=patternpolygon.strokeWidth=POLYGON_STROKE_WIDTH_PX.toFloat()polygon.strokeColor=strokeColorpolygon.fillColor=fillColor}}
Set up your development project

Follow these steps to create the tutorial project in Android Studio.
- Download andinstall Android Studio.
- Add theGoogle Play services package to AndroidStudio.
- Clone or download the Google Maps Android API v2 Samples repositoryif you didn't do that when you started reading this tutorial.
Import the tutorial project:
- In Android Studio, selectFile > New > Import Project.
- Go to the location where you saved the Google Maps Android API v2 Samplesrepository after downloading it.
- Find thePolygons project at this location:
PATH-TO-SAVED-REPO/android-samples/tutorials/java/Polygons(Java) orPATH-TO-SAVED-REPO/android-samples/tutorials/kotlin/Polygons(Kotlin) - Select the project directory, then clickOpen. Android Studio now buildsyour project, using the Gradle build tool.
Enable the necessary APIs and get an API key
To complete this tutorial, you need a Google Cloud project with the necessaryAPIs enabled and an API key that's authorized to use the Maps SDK for Android.For more details, see:
Add the API key to your app
- Open your project's
local.propertiesfile. Add the following string and then replace
YOUR_API_KEYwith the value ofyour API key:MAPS_API_KEY=YOUR_API_KEYWhen you build your app, theSecrets Gradle Plugin for Android will copy the API key and make it available as a build variable in theAndroid manifest, as explainedbelow.
Build and run your app
To build and run the app:
Connect an Android device to your computer. Follow theinstructions to enable developer options on your Androiddevice and configure your system to detect the device.
Alternatively, you can use theAndroid Virtual Device (AVD) Managerto configure a virtual device. When choosing an emulator, make sure you pickan image that includes the Google APIs. For more details, seeSet Up an Android Studio Project.
In Android Studio, click theRun menu option (or the play button icon).Choose a device as prompted.
Android Studio invokes Gradle to build the app, and then runs the app onthe device or on the emulator.
You should see a map with two polygons overlaid on top of Australia, similar tothe image on this page.
Troubleshooting:
- If you don't see a map, check that you've obtained an API key and added it tothe app,as described above. Check the log in AndroidStudio'sAndroid Monitor for error messages about the API key.
- Use theAndroid Studio debugging tools to view logs and debugthe app.
Understand the code
This part of the tutorial explains the most significant parts of thePolygons app, to help you understand how to build a similarapp.
Check your Android manifest
Note the following elements in your app'sAndroidManifest.xml file:
Add a
meta-dataelement to embed the version of Google Play services thatthe app was compiled with.<meta-dataandroid:name="com.google.android.gms.version"android:value="@integer/google_play_services_version"/>Add a
meta-dataelement specifying your API key. The sample accompanyingthis tutorial maps the value for the API key to a build variable matchingthe name of the key you defined earlier,MAPS_API_KEY.When you build your app, theSecrets Gradle Plugin for Androidwill make the keys in yourlocal.propertiesfile available as manifest buildvariables.<meta-dataandroid:name="com.google.android.geo.API_KEY"android:value="${MAPS_API_KEY}"/>In your
build.gradlefile, the following line passes your API key to yourAndroid manifest.id 'com.google.android.libraries.mapsplatform.secrets-gradle-plugin'
Below is a complete example of a manifest:
<?xmlversion="1.0"encoding="utf-8"?><!--Copyright2020GoogleLLCLicensedundertheApacheLicense,Version2.0(the"License");youmaynotusethisfileexceptincompliancewiththeLicense.YoumayobtainacopyoftheLicenseathttp://www.apache.org/licenses/LICENSE-2.0Unlessrequiredbyapplicablelaworagreedtoinwriting,softwaredistributedundertheLicenseisdistributedonan"AS IS"BASIS,WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied.SeetheLicenseforthespecificlanguagegoverningpermissionsandlimitationsundertheLicense.--><manifestxmlns:android="http://schemas.android.com/apk/res/android"><applicationandroid:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:supportsRtl="true"android:theme="@style/AppTheme"><meta-dataandroid:name="com.google.android.gms.version"android:value="@integer/google_play_services_version"/><!--TheAPIkeyforGoogleMaps-basedAPIs.--><meta-dataandroid:name="com.google.android.geo.API_KEY"android:value="${MAPS_API_KEY}"/><activityandroid:name="com.example.polygons.PolyActivity"android:exported="true"android:label="@string/title_activity_maps"><intent-filter><actionandroid:name="android.intent.action.MAIN"/><categoryandroid:name="android.intent.category.LAUNCHER"/></intent-filter></activity></application></manifest>
Add a map
Display a map, using the Maps SDK for Android.
Add a
<fragment>element to your activity's layout file,activity_maps.xml. This element defines aSupportMapFragmentto act as a container for the mapand to provide access to theGoogleMapobject. The tutorialuses the Android support library version of the map fragment, to ensurebackward compatibility with earlier versions of the Android framework.<!--Copyright2020GoogleLLCLicensedundertheApacheLicense,Version2.0(the"License");youmaynotusethisfileexceptincompliancewiththeLicense.YoumayobtainacopyoftheLicenseathttp://www.apache.org/licenses/LICENSE-2.0Unlessrequiredbyapplicablelaworagreedtoinwriting,softwaredistributedundertheLicenseisdistributedonan"AS IS"BASIS,WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied.SeetheLicenseforthespecificlanguagegoverningpermissionsandlimitationsundertheLicense.--><fragmentxmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:id="@+id/map"android:name="com.google.android.gms.maps.SupportMapFragment"android:layout_width="match_parent"android:layout_height="match_parent"tools:context="com.example.polygons.PolyActivity"/>
In your activity's
onCreate()method, set the layoutfile as the content view. Get a handle to the map fragment by callingFragmentManager.findFragmentById(). Then usegetMapAsync()to register for the map callback:Java
@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);// Retrieve the content view that renders the map.setContentView(R.layout.activity_maps);// Get the SupportMapFragment and request notification when the map is ready to be used.SupportMapFragmentmapFragment=(SupportMapFragment)getSupportFragmentManager().findFragmentById(R.id.map);mapFragment.getMapAsync(this);}
Kotlin
overridefunonCreate(savedInstanceState:Bundle?){super.onCreate(savedInstanceState)// Retrieve the content view that renders the map.setContentView(R.layout.activity_maps)// Get the SupportMapFragment and request notification when the map is ready to be used.valmapFragment=supportFragmentManager.findFragmentById(R.id.map)asSupportMapFragment?mapFragment?.getMapAsync(this)}
Implement the
OnMapReadyCallbackinterface andoverride theonMapReady()method. The API invokes thiscallback when theGoogleMapobject is available, so you can addobjects to the map and further customize it for your app:Java
publicclassPolyActivityextendsAppCompatActivityimplementsOnMapReadyCallback,GoogleMap.OnPolylineClickListener,GoogleMap.OnPolygonClickListener{@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);// Retrieve the content view that renders the map.setContentView(R.layout.activity_maps);// Get the SupportMapFragment and request notification when the map is ready to be used.SupportMapFragmentmapFragment=(SupportMapFragment)getSupportFragmentManager().findFragmentById(R.id.map);mapFragment.getMapAsync(this);}/** * Manipulates the map when it's available. * The API invokes this callback when the map is ready to be used. * This is where we can add markers or lines, add listeners or move the camera. * In this tutorial, we add polylines and polygons to represent routes and areas on the map. */@OverridepublicvoidonMapReady(GoogleMapgoogleMap){// Add polylines to the map.// Polylines are useful to show a route or some other connection between points.Polylinepolyline1=googleMap.addPolyline(newPolylineOptions().clickable(true).add(newLatLng(-35.016,143.321),newLatLng(-34.747,145.592),newLatLng(-34.364,147.891),newLatLng(-33.501,150.217),newLatLng(-32.306,149.248),newLatLng(-32.491,147.309)));// Position the map's camera near Alice Springs in the center of Australia,// and set the zoom factor so most of Australia shows on the screen.googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(newLatLng(-23.684,133.903),4));// Set listeners for click events.googleMap.setOnPolylineClickListener(this);googleMap.setOnPolygonClickListener(this);}
Kotlin
classPolyActivity:AppCompatActivity(),OnMapReadyCallback,OnPolylineClickListener,OnPolygonClickListener{overridefunonCreate(savedInstanceState:Bundle?){super.onCreate(savedInstanceState)// Retrieve the content view that renders the map.setContentView(R.layout.activity_maps)// Get the SupportMapFragment and request notification when the map is ready to be used.valmapFragment=supportFragmentManager.findFragmentById(R.id.map)asSupportMapFragment?mapFragment?.getMapAsync(this)}/** * Manipulates the map when it's available. * The API invokes this callback when the map is ready to be used. * This is where we can add markers or lines, add listeners or move the camera. * In this tutorial, we add polylines and polygons to represent routes and areas on the map. */overridefunonMapReady(googleMap:GoogleMap){// Add polylines to the map.// Polylines are useful to show a route or some other connection between points.valpolyline1=googleMap.addPolyline(PolylineOptions().clickable(true).add(LatLng(-35.016,143.321),LatLng(-34.747,145.592),LatLng(-34.364,147.891),LatLng(-33.501,150.217),LatLng(-32.306,149.248),LatLng(-32.491,147.309)))// Position the map's camera near Alice Springs in the center of Australia,// and set the zoom factor so most of Australia shows on the screen.googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(-23.684,133.903),4f))// Set listeners for click events.googleMap.setOnPolylineClickListener(this)googleMap.setOnPolygonClickListener(this)}
Add a polyline to draw a line on the map
APolyline is a series of connected line segments. Polylines areuseful to represent routes, paths, or other connections between locations on themap.
Create a
PolylineOptionsobject and add points to it.Each point represents a location on the map, which you define with aLatLngobject containing latitude and longitude values. Thecode sample below creates a polyline with 6 points.Call
GoogleMap.addPolyline()to add the polyline to the map.Java
Polylinepolyline1=googleMap.addPolyline(newPolylineOptions().clickable(true).add(newLatLng(-35.016,143.321),newLatLng(-34.747,145.592),newLatLng(-34.364,147.891),newLatLng(-33.501,150.217),newLatLng(-32.306,149.248),newLatLng(-32.491,147.309)));
Kotlin
valpolyline1=googleMap.addPolyline(PolylineOptions().clickable(true).add(LatLng(-35.016,143.321),LatLng(-34.747,145.592),LatLng(-34.364,147.891),LatLng(-33.501,150.217),LatLng(-32.306,149.248),LatLng(-32.491,147.309)))
Set the polyline'sclickable option totrue if you want to handle clickevents on the polyline. There's more about event handling later in thistutorial.
Store arbitrary data with a polyline
You can store arbitrary data objects with polylines and other geometry objects.
Call
Polyline.setTag()to store a data object with thepolyline. The code below defines an arbitrary tag (A) indicating a type ofpolyline.Java
Polylinepolyline1=googleMap.addPolyline(newPolylineOptions().clickable(true).add(newLatLng(-35.016,143.321),newLatLng(-34.747,145.592),newLatLng(-34.364,147.891),newLatLng(-33.501,150.217),newLatLng(-32.306,149.248),newLatLng(-32.491,147.309)));// Store a data object with the polyline, used here to indicate an arbitrary type.polyline1.setTag("A");
Kotlin
valpolyline1=googleMap.addPolyline(PolylineOptions().clickable(true).add(LatLng(-35.016,143.321),LatLng(-34.747,145.592),LatLng(-34.364,147.891),LatLng(-33.501,150.217),LatLng(-32.306,149.248),LatLng(-32.491,147.309)))// Store a data object with the polyline, used here to indicate an arbitrary type.polyline1.tag="A
Retrieve the data using
Polyline.getTag(), as thenext section shows.
Add custom styling to your polyline
You can specify various styling properties in thePolylineOptions object. Styling options include the strokecolor, stroke width, stroke pattern, joint types, and start and end caps. If youdon't specify a particular property, the API uses a default for thatproperty.
The following code applies a round cap to the end of the line, and a differentstart cap depending on the polyline'stype, where the type is an arbitraryproperty stored in the data object for the polyline. The sample also specifiesa stroke width, stroke color, and joint type:
Java
privatestaticfinalintCOLOR_BLACK_ARGB=0xff000000;privatestaticfinalintPOLYLINE_STROKE_WIDTH_PX=12;/** * Styles the polyline, based on type. * @param polyline The polyline object that needs styling. */privatevoidstylePolyline(Polylinepolyline){Stringtype="";// Get the data object stored with the polyline.if(polyline.getTag()!=null){type=polyline.getTag().toString();}switch(type){// If no type is given, allow the API to use the default.case"A":// Use a custom bitmap as the cap at the start of the line.polyline.setStartCap(newCustomCap(BitmapDescriptorFactory.fromResource(R.drawable.ic_arrow),10));break;case"B":// Use a round cap at the start of the line.polyline.setStartCap(newRoundCap());break;}polyline.setEndCap(newRoundCap());polyline.setWidth(POLYLINE_STROKE_WIDTH_PX);polyline.setColor(COLOR_BLACK_ARGB);polyline.setJointType(JointType.ROUND);}
Kotlin
privatevalCOLOR_BLACK_ARGB=-0x1000000privatevalPOLYLINE_STROKE_WIDTH_PX=12/** * Styles the polyline, based on type. * @param polyline The polyline object that needs styling. */privatefunstylePolyline(polyline:Polyline){// Get the data object stored with the polyline.valtype=polyline.tag?.toString()?:""when(type){"A"->{// Use a custom bitmap as the cap at the start of the line.polyline.startCap=CustomCap(BitmapDescriptorFactory.fromResource(R.drawable.ic_arrow),10f)}"B"->{// Use a round cap at the start of the line.polyline.startCap=RoundCap()}}polyline.endCap=RoundCap()polyline.width=POLYLINE_STROKE_WIDTH_PX.toFloat()polyline.color=COLOR_BLACK_ARGBpolyline.jointType=JointType.ROUND}
The above code specifies a custom bitmap for the start cap of the type Apolyline, and specifies a reference stroke width of 10 pixels. The API scalesthe bitmap based on the reference stroke width. When specifying the referencestroke width, supply the width that you used when designing the bitmap image, atthe original dimension of the image. Hint: Open your bitmap image at 100% zoomin an image editor, and plot the desired width of the line stroke relative tothe image.
Read more aboutline caps and other options forcustomizing shapes.
Handle click events on the polyline
Make the polyline clickable by calling
Polyline.setClickable(). (By default, polylines arenot clickable and your app will not receive a notification when the usertaps a polyline.)Implement the
OnPolylineClickListenerinterfaceand callGoogleMap.setOnPolylineClickListener()to set the listener on the map:Java
publicclassPolyActivityextendsAppCompatActivityimplementsOnMapReadyCallback,GoogleMap.OnPolylineClickListener,GoogleMap.OnPolygonClickListener{@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);// Retrieve the content view that renders the map.setContentView(R.layout.activity_maps);// Get the SupportMapFragment and request notification when the map is ready to be used.SupportMapFragmentmapFragment=(SupportMapFragment)getSupportFragmentManager().findFragmentById(R.id.map);mapFragment.getMapAsync(this);}/** * Manipulates the map when it's available. * The API invokes this callback when the map is ready to be used. * This is where we can add markers or lines, add listeners or move the camera. * In this tutorial, we add polylines and polygons to represent routes and areas on the map. */@OverridepublicvoidonMapReady(GoogleMapgoogleMap){// Add polylines to the map.// Polylines are useful to show a route or some other connection between points.Polylinepolyline1=googleMap.addPolyline(newPolylineOptions().clickable(true).add(newLatLng(-35.016,143.321),newLatLng(-34.747,145.592),newLatLng(-34.364,147.891),newLatLng(-33.501,150.217),newLatLng(-32.306,149.248),newLatLng(-32.491,147.309)));// Position the map's camera near Alice Springs in the center of Australia,// and set the zoom factor so most of Australia shows on the screen.googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(newLatLng(-23.684,133.903),4));// Set listeners for click events.googleMap.setOnPolylineClickListener(this);googleMap.setOnPolygonClickListener(this);}
Kotlin
classPolyActivity:AppCompatActivity(),OnMapReadyCallback,OnPolylineClickListener,OnPolygonClickListener{overridefunonCreate(savedInstanceState:Bundle?){super.onCreate(savedInstanceState)// Retrieve the content view that renders the map.setContentView(R.layout.activity_maps)// Get the SupportMapFragment and request notification when the map is ready to be used.valmapFragment=supportFragmentManager.findFragmentById(R.id.map)asSupportMapFragment?mapFragment?.getMapAsync(this)}/** * Manipulates the map when it's available. * The API invokes this callback when the map is ready to be used. * This is where we can add markers or lines, add listeners or move the camera. * In this tutorial, we add polylines and polygons to represent routes and areas on the map. */overridefunonMapReady(googleMap:GoogleMap){// Add polylines to the map.// Polylines are useful to show a route or some other connection between points.valpolyline1=googleMap.addPolyline(PolylineOptions().clickable(true).add(LatLng(-35.016,143.321),LatLng(-34.747,145.592),LatLng(-34.364,147.891),LatLng(-33.501,150.217),LatLng(-32.306,149.248),LatLng(-32.491,147.309)))// Position the map's camera near Alice Springs in the center of Australia,// and set the zoom factor so most of Australia shows on the screen.googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(-23.684,133.903),4f))// Set listeners for click events.googleMap.setOnPolylineClickListener(this)googleMap.setOnPolygonClickListener(this)}
Override the
onPolylineClick()callback method. Thefollowing example alternates the stroke pattern of the line between solid anddotted, each time the user clicks the polyline:Java
privatestaticfinalintPATTERN_GAP_LENGTH_PX=20;privatestaticfinalPatternItemDOT=newDot();privatestaticfinalPatternItemGAP=newGap(PATTERN_GAP_LENGTH_PX);// Create a stroke pattern of a gap followed by a dot.privatestaticfinalList<PatternItem>PATTERN_POLYLINE_DOTTED=Arrays.asList(GAP,DOT);/** * Listens for clicks on a polyline. * @param polyline The polyline object that the user has clicked. */@OverridepublicvoidonPolylineClick(Polylinepolyline){// Flip from solid stroke to dotted stroke pattern.if((polyline.getPattern()==null)||(!polyline.getPattern().contains(DOT))){polyline.setPattern(PATTERN_POLYLINE_DOTTED);}else{// The default pattern is a solid stroke.polyline.setPattern(null);}Toast.makeText(this,"Route type "+polyline.getTag().toString(),Toast.LENGTH_SHORT).show();}
Kotlin
privatevalPATTERN_GAP_LENGTH_PX=20privatevalDOT:PatternItem=Dot()privatevalGAP:PatternItem=Gap(PATTERN_GAP_LENGTH_PX.toFloat())// Create a stroke pattern of a gap followed by a dot.privatevalPATTERN_POLYLINE_DOTTED=listOf(GAP,DOT)/** * Listens for clicks on a polyline. * @param polyline The polyline object that the user has clicked. */overridefunonPolylineClick(polyline:Polyline){// Flip from solid stroke to dotted stroke pattern.if(polyline.pattern==null||!polyline.pattern!!.contains(DOT)){polyline.pattern=PATTERN_POLYLINE_DOTTED}else{// The default pattern is a solid stroke.polyline.pattern=null}Toast.makeText(this,"Route type "+polyline.tag.toString(),Toast.LENGTH_SHORT).show()}
Add polygons to represent areas on the map
APolygon is a shape consisting of a series of coordinates in anordered sequence, similar to aPolyline. The difference is thatpolygon defines a closed area with a fillable interior, while a polylineis open ended.
Create a
PolygonOptionsobject and add points to it.Each point represents a location on the map, which you define with aLatLngobject containing latitude and longitude values. Thecode sample below creates a polygon with 4 points.Make the polygon clickable by calling
Polygon.setClickable(). (By default, polygons arenot clickable and your app will not receive a notification when the usertaps a polygon.) Handling polygon click events is similar to handling theevents on polylines, described earlier in this tutorial.Call
GoogleMap.addPolygon()to add the polygon to the map.Call
Polygon.setTag()to store a data object with thepolygon. The code below defines an arbitrary type (alpha) for the polygon.Java
// Add polygons to indicate areas on the map.Polygonpolygon1=googleMap.addPolygon(newPolygonOptions().clickable(true).add(newLatLng(-27.457,153.040),newLatLng(-33.852,151.211),newLatLng(-37.813,144.962),newLatLng(-34.928,138.599)));// Store a data object with the polygon, used here to indicate an arbitrary type.polygon1.setTag("alpha");
Kotlin
// Add polygons to indicate areas on the map.valpolygon1=googleMap.addPolygon(PolygonOptions().clickable(true).add(LatLng(-27.457,153.040),LatLng(-33.852,151.211),LatLng(-37.813,144.962),LatLng(-34.928,138.599)))// Store a data object with the polygon, used here to indicate an arbitrary type.polygon1.tag="alpha"// Style the polygon.
Add custom styling to your polygon
You can specify a number of styling properties in thePolygonOptions object. Styling options include the strokecolor, stroke width, stroke pattern, stroke joint types, and fill color. If youdon't specify a particular property, the API uses a default for thatproperty.
The following code applies specific colors and stroke patterns depending on thepolygon'stype, where the type is an arbitrary property stored in the dataobject for the polygon:
Java
privatestaticfinalintCOLOR_WHITE_ARGB=0xffffffff;privatestaticfinalintCOLOR_DARK_GREEN_ARGB=0xff388E3C;privatestaticfinalintCOLOR_LIGHT_GREEN_ARGB=0xff81C784;privatestaticfinalintCOLOR_DARK_ORANGE_ARGB=0xffF57F17;privatestaticfinalintCOLOR_LIGHT_ORANGE_ARGB=0xffF9A825;privatestaticfinalintPOLYGON_STROKE_WIDTH_PX=8;privatestaticfinalintPATTERN_DASH_LENGTH_PX=20;privatestaticfinalPatternItemDASH=newDash(PATTERN_DASH_LENGTH_PX);// Create a stroke pattern of a gap followed by a dash.privatestaticfinalList<PatternItem>PATTERN_POLYGON_ALPHA=Arrays.asList(GAP,DASH);// Create a stroke pattern of a dot followed by a gap, a dash, and another gap.privatestaticfinalList<PatternItem>PATTERN_POLYGON_BETA=Arrays.asList(DOT,GAP,DASH,GAP);/** * Styles the polygon, based on type. * @param polygon The polygon object that needs styling. */privatevoidstylePolygon(Polygonpolygon){Stringtype="";// Get the data object stored with the polygon.if(polygon.getTag()!=null){type=polygon.getTag().toString();}List<PatternItem>pattern=null;intstrokeColor=COLOR_BLACK_ARGB;intfillColor=COLOR_WHITE_ARGB;switch(type){// If no type is given, allow the API to use the default.case"alpha":// Apply a stroke pattern to render a dashed line, and define colors.pattern=PATTERN_POLYGON_ALPHA;strokeColor=COLOR_DARK_GREEN_ARGB;fillColor=COLOR_LIGHT_GREEN_ARGB;break;case"beta":// Apply a stroke pattern to render a line of dots and dashes, and define colors.pattern=PATTERN_POLYGON_BETA;strokeColor=COLOR_DARK_ORANGE_ARGB;fillColor=COLOR_LIGHT_ORANGE_ARGB;break;}polygon.setStrokePattern(pattern);polygon.setStrokeWidth(POLYGON_STROKE_WIDTH_PX);polygon.setStrokeColor(strokeColor);polygon.setFillColor(fillColor);}
Kotlin
privatevalCOLOR_WHITE_ARGB=-0x1privatevalCOLOR_DARK_GREEN_ARGB=-0xc771c4privatevalCOLOR_LIGHT_GREEN_ARGB=-0x7e387cprivatevalCOLOR_DARK_ORANGE_ARGB=-0xa80e9privatevalCOLOR_LIGHT_ORANGE_ARGB=-0x657dbprivatevalPOLYGON_STROKE_WIDTH_PX=8privatevalPATTERN_DASH_LENGTH_PX=20privatevalDASH:PatternItem=Dash(PATTERN_DASH_LENGTH_PX.toFloat())// Create a stroke pattern of a gap followed by a dash.privatevalPATTERN_POLYGON_ALPHA=listOf(GAP,DASH)// Create a stroke pattern of a dot followed by a gap, a dash, and another gap.privatevalPATTERN_POLYGON_BETA=listOf(DOT,GAP,DASH,GAP)/** * Styles the polygon, based on type. * @param polygon The polygon object that needs styling. */privatefunstylePolygon(polygon:Polygon){// Get the data object stored with the polygon.valtype=polygon.tag?.toString()?:""varpattern:List<PatternItem>?=nullvarstrokeColor=COLOR_BLACK_ARGBvarfillColor=COLOR_WHITE_ARGBwhen(type){"alpha"->{// Apply a stroke pattern to render a dashed line, and define colors.pattern=PATTERN_POLYGON_ALPHAstrokeColor=COLOR_DARK_GREEN_ARGBfillColor=COLOR_LIGHT_GREEN_ARGB}"beta"->{// Apply a stroke pattern to render a line of dots and dashes, and define colors.pattern=PATTERN_POLYGON_BETAstrokeColor=COLOR_DARK_ORANGE_ARGBfillColor=COLOR_LIGHT_ORANGE_ARGB}}polygon.strokePattern=patternpolygon.strokeWidth=POLYGON_STROKE_WIDTH_PX.toFloat()polygon.strokeColor=strokeColorpolygon.fillColor=fillColor}
Read more aboutstroke patterns and other options forcustomizing shapes.
Congratulations! You've built an Android app containing a Google map, with polygons to represent areas on the map and polylines to represent routes or other connections between locations. You've also learned how to use theMaps SDK for Android.Next steps
Learn about theCircle object. Circles are similar to polygons buthave properties that reflect the shape of a circle.
Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 4.0 License, and code samples are licensed under theApache 2.0 License. For details, see theGoogle Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.
Last updated 2025-11-21 UTC.