Add a marker with info window to a map
Stay organized with collections
Save and categorize content based on your preferences.
Page Summary
-
The code provides a comprehensive example of using markers on a Google Map in an Android application, demonstrating features like marker placement, customization, and event handling.
-
It showcases custom info windows with layouts and data, displaying information about marked locations.
-
Users can interact with markers through clicks, drags, and info window interactions, triggering events like animations or data updates.
-
The code utilizes UI elements such as SeekBar and CheckBox to control marker appearance and behavior, offering user customization.
-
Although not explicitly demonstrated, the code hints at the possibility of overlapping markers and the need for clustering in real-world scenarios by placing multiple markers in Darwin with different z-indexes.
This example identifies a location on the map with a marker. When the user taps a marker, an info window appears.
For more information, see the documentation.
Get started
Before you can try the sample code, you must configure your development environment. For more information, see Maps SDK for Android code samples.
View the code
Kotlin
classMarkerDemoActivity: SamplesBaseActivity(), OnMarkerClickListener, OnInfoWindowClickListener, OnMarkerDragListener, OnInfoWindowLongClickListener, OnInfoWindowCloseListener, OnMapAndViewReadyListener.OnGlobalLayoutAndMapReadyListener{ privatevalTAG=MarkerDemoActivity::class.java.name /** This is ok to be lateinit as it is initialised in onMapReady */ privatelateinitvarmap:GoogleMap /** * Keeps track of the last selected marker (though it may no longer be selected). This is * useful for refreshing the info window. * * Must be nullable as it is null when no marker has been selected */ privatevarlastSelectedMarker:Marker? =null privatevalmarkerRainbow=ArrayList<Marker>() /** map to store place names and locations */ privatevalplaces=mapOf( "BRISBANE"toLatLng(-27.47093,153.0235), "MELBOURNE"toLatLng(-37.81319,144.96298), "DARWIN"toLatLng(-12.4634,130.8456), "SYDNEY"toLatLng(-33.87365,151.20689), "ADELAIDE"toLatLng(-34.92873,138.59995), "PERTH"toLatLng(-31.952854,115.857342), "ALICE_SPRINGS"toLatLng(-24.6980,133.8807) ) privatelateinitvarbinding:com.example.common_ui.databinding.MarkerDemoBinding privatevalrandom=Random() /** Demonstrates customizing the info window and/or its contents. */ internalinnerclassCustomInfoWindowAdapter:InfoWindowAdapter{ // These are both view groups containing an ImageView with id "badge" and two // TextViews with id "title" and "snippet". privatevalwindow:View=layoutInflater.inflate(R.layout.custom_info_window,null) privatevalcontents:View=layoutInflater.inflate(R.layout.custom_info_contents,null) overridefungetInfoWindow(marker:Marker):View? { if(binding.customInfoWindowOptions.checkedRadioButtonId!=R.id.custom_info_window){ // This means that getInfoContents will be called. returnnull } render(marker,window) returnwindow } overridefungetInfoContents(marker:Marker):View? { if(binding.customInfoWindowOptions.checkedRadioButtonId!=R.id.custom_info_contents){ // This means that the default info contents will be used. returnnull } render(marker,contents) returncontents } privatefunrender(marker:Marker,view:View){ valbadge=when(marker.title!!){ "Brisbane"->R.drawable.badge_qld "Adelaide"->R.drawable.badge_sa "Sydney"->R.drawable.badge_nsw "Melbourne"->R.drawable.badge_victoria "Perth"->R.drawable.badge_wa in"Darwin Marker 1".."Darwin Marker 4"->R.drawable.badge_nt else->0// Passing 0 to setImageResource will clear the image view. } view.findViewById<ImageView>(R.id.badge).setImageResource(badge) // Set the title and snippet for the custom info window valtitle:String?=marker.title valtitleUi=view.findViewById<TextView>(R.id.title) if(title!=null){ // Spannable string allows us to edit the formatting of the text. titleUi.text=SpannableString(title).apply{ setSpan(ForegroundColorSpan(Color.RED),0,length,0) } }else{ titleUi.text="" } valsnippet:String?=marker.snippet valsnippetUi=view.findViewById<TextView>(R.id.snippet) if(snippet!=null && snippet.length > 12){ snippetUi.text=SpannableString(snippet).apply{ setSpan(ForegroundColorSpan(Color.MAGENTA),0,10,0) setSpan(ForegroundColorSpan(Color.BLUE),12,snippet.length,0) } }else{ snippetUi.text="" } } } overridefunonCreate(savedInstanceState:Bundle?){ super.onCreate(savedInstanceState) binding=com.example.common_ui.databinding.MarkerDemoBinding.inflate(layoutInflater) setContentView(binding.root) binding.rotationSeekBar.apply{ max=360 setOnSeekBarChangeListener(object:OnSeekBarChangeListener{ /** Called when the Rotation progress bar is moved */ overridefunonProgressChanged(seekBar:SeekBar?,progress:Int,fromUser:Boolean){ valrotation=seekBar?.progress?.toFloat() checkReadyThen{markerRainbow.map{it.rotation=rotation?:0f}} } overridefunonStartTrackingTouch(p0:SeekBar?){ // do nothing } overridefunonStopTrackingTouch(p0:SeekBar?){ //do nothing } }) } binding.customInfoWindowOptions.apply{ setOnCheckedChangeListener{_,_-> if(lastSelectedMarker?.isInfoWindowShown==true){ // Refresh the info window when the info window's content has changed. // must deal with the possibility that lastSelectedMarker has changed in // another thread between the null check and this line, do this with !! lastSelectedMarker?.showInfoWindow() } } } binding.clearMap.setOnClickListener{onClearMap()} binding.resetMap.setOnClickListener{onResetMap()} binding.flat.setOnClickListener{onToggleFlat()} valmapFragment=supportFragmentManager.findFragmentById(R.id.map)asSupportMapFragment OnMapAndViewReadyListener(mapFragment,this) applyInsets(binding.mapContainer) } /** * This is the callback that is triggered when the GoogleMap has loaded and is ready for use */ overridefunonMapReady(googleMap:GoogleMap?){ // return early if the map was not initialised properly map=googleMap?:return // create bounds that encompass every location we reference valboundsBuilder=LatLngBounds.Builder() // include all places we have markers for on the map places.keys.map{place->boundsBuilder.include(places.getValue(place))} valbounds=boundsBuilder.build() with(map){ // Hide the zoom controls as the button panel will cover it. uiSettings.isZoomControlsEnabled=false // Setting an info window adapter allows us to change the both the contents and // look of the info window. setInfoWindowAdapter(CustomInfoWindowAdapter()) // Set listeners for marker events. See the bottom of this class for their behavior. setOnMarkerClickListener(this@MarkerDemoActivity) setOnInfoWindowClickListener(this@MarkerDemoActivity) setOnMarkerDragListener(this@MarkerDemoActivity) setOnInfoWindowCloseListener(this@MarkerDemoActivity) setOnInfoWindowLongClickListener(this@MarkerDemoActivity) // Override the default content description on the view, for accessibility mode. // Ideally this string would be localised. setContentDescription("Map with lots of markers.") moveCamera(CameraUpdateFactory.newLatLngBounds(bounds,50)) } // Add lots of markers to the googleMap. addMarkersToMap() } /** * Show all the specified markers on the map */ privatefunaddMarkersToMap(){ valplaceDetailsMap=mutableMapOf( // Uses a coloured icon "BRISBANE"toPlaceDetails( position=places.getValue("BRISBANE"), title="Brisbane", snippet="Population: 2,074,200", icon=BitmapDescriptorFactory .defaultMarker(BitmapDescriptorFactory.HUE_AZURE) ), // Uses a custom icon with the info window popping out of the center of the icon. "SYDNEY"toPlaceDetails( position=places.getValue("SYDNEY"), title="Sydney", snippet="Population: 4,627,300", icon=BitmapDescriptorFactory.fromResource(R.drawable.arrow), infoWindowAnchorX=0.5f, infoWindowAnchorY=0.5f ), // Will create a draggable marker. Long press to drag. "MELBOURNE"toPlaceDetails( position=places.getValue("MELBOURNE"), title="Melbourne", snippet="Population: 4,137,400", draggable=true ), // Use a vector drawable resource as a marker icon. "ALICE_SPRINGS"toPlaceDetails( position=places.getValue("ALICE_SPRINGS"), title="Alice Springs", icon=vectorToBitmap( R.drawable.ic_android,"#A4C639".toColorInt()) ), // More markers for good measure "PERTH"toPlaceDetails( position=places.getValue("PERTH"), title="Perth", snippet="Population: 1,738,800" ), "ADELAIDE"toPlaceDetails( position=places.getValue("ADELAIDE"), title="Adelaide", snippet="Population: 1,213,000" ) ) // add 4 markers on top of each other in Darwin with varying z-indexes (0until4).map{ placeDetailsMap.put( "DARWIN ${it+1}",PlaceDetails( position=places.getValue("DARWIN"), title="Darwin Marker ${it+1}", snippet="z-index initially ${it+1}", zIndex=it.toFloat() ) ) } // place markers for each of the defined locations placeDetailsMap.keys.map{ with(placeDetailsMap.getValue(it)){ map.addMarker(MarkerOptions() .position(position) .title(title) .snippet(snippet) .icon(icon) .infoWindowAnchor(infoWindowAnchorX,infoWindowAnchorY) .draggable(draggable) .zIndex(zIndex)) } } // Creates a marker rainbow demonstrating how to create default marker icons of different // hues (colors). valnumMarkersInRainbow=12 (0untilnumMarkersInRainbow).mapTo(markerRainbow){ map.addMarker(MarkerOptions().apply{ position(LatLng( -30+10*sin(it*Math.PI/(numMarkersInRainbow-1)), 135-10*cos(it*Math.PI/(numMarkersInRainbow-1)) )) title("Marker $it") icon(BitmapDescriptorFactory.defaultMarker((it*360/numMarkersInRainbow) .toFloat())) flat(binding.flat.isChecked) rotation(binding.rotationSeekBar.progress.toFloat()) })!! } } /** * Demonstrates converting a [Drawable] to a [BitmapDescriptor], * for use as a marker icon. */ privatefunvectorToBitmap(@DrawableResid:Int,@ColorIntcolor:Int):BitmapDescriptor{ valvectorDrawable:Drawable? =ResourcesCompat.getDrawable(resources,id,null) if(vectorDrawable==null){ Log.e(TAG,"Resource not found") returnBitmapDescriptorFactory.defaultMarker() } valbitmap=createBitmap( vectorDrawable.intrinsicWidth, vectorDrawable.intrinsicHeight, Bitmap.Config.ARGB_8888 ) valcanvas=Canvas(bitmap) vectorDrawable.setBounds(0,0,canvas.width,canvas.height) DrawableCompat.setTint(vectorDrawable,color) vectorDrawable.draw(canvas) returnBitmapDescriptorFactory.fromBitmap(bitmap) } privatefunonClearMap(){ checkReadyThen{map.clear()} } privatefunonResetMap(){ checkReadyThen{ map.clear() addMarkersToMap() } } privatefunonToggleFlat(){ checkReadyThen{markerRainbow.map{marker->marker.isFlat=binding.flat.isChecked}} } // // Marker related listeners. // overridefunonMarkerClick(marker:Marker):Boolean{ // Markers have a z-index that is settable and gettable. marker.zIndex+=1.0f Toast.makeText(this,"${marker.title} z-index set to ${marker.zIndex}", Toast.LENGTH_SHORT).show() lastSelectedMarker=marker if(marker.position==places.getValue("PERTH")){ // This causes the marker at Perth to bounce into position when it is clicked. valhandler=Handler(Looper.getMainLooper()) valstart=SystemClock.uptimeMillis() valduration=1500 valinterpolator=BounceInterpolator() handler.post(object:Runnable{ overridefunrun(){ valelapsed=SystemClock.uptimeMillis()-start valt= (1-interpolator.getInterpolation(elapsed.toFloat()/duration)).coerceAtLeast( 0f ) marker.setAnchor(0.5f,1.0f+2*t) // Post again 16ms later. if(t > 0.0){ handler.postDelayed(this,16) } } }) }elseif(marker.position==places.getValue("ADELAIDE")){ // This causes the marker at Adelaide to change color and alpha. marker.apply{ setIcon(BitmapDescriptorFactory.defaultMarker(random.nextFloat()*360)) alpha=random.nextFloat() } } // We return false to indicate that we have not consumed the event and that we wish // for the default behavior to occur (which is for the camera to move such that the // marker is centered and for the marker's info window to open, if it has one). returnfalse } overridefunonInfoWindowClick(marker:Marker){ Toast.makeText(this,"Click Info Window",Toast.LENGTH_SHORT).show() } overridefunonInfoWindowClose(marker:Marker){ Toast.makeText(this,"Close Info Window",Toast.LENGTH_SHORT).show() } overridefunonInfoWindowLongClick(marker:Marker){ Toast.makeText(this,"Info Window long click",Toast.LENGTH_SHORT).show() } overridefunonMarkerDragStart(marker:Marker){ binding.topText.text=getString(R.string.on_marker_drag_start) } overridefunonMarkerDragEnd(marker:Marker){ binding.topText.text=getString(R.string.on_marker_drag_end) } overridefunonMarkerDrag(marker:Marker){ binding.topText.text=getString(R.string.on_marker_drag,marker.position.latitude,marker.position.longitude) } /** * Checks if the map is ready, the executes the provided lambda function * * @param stuffToDo the code to be executed if the map is ready */ privatefuncheckReadyThen(stuffToDo:()->Unit){ if(!::map.isInitialized){ Toast.makeText(this,R.string.map_not_ready,Toast.LENGTH_SHORT).show() }else{ stuffToDo() } } }
Java
publicclass MarkerDemoActivityextendsSamplesBaseActivityimplements OnMarkerClickListener, OnInfoWindowClickListener, OnMarkerDragListener, OnSeekBarChangeListener, OnInfoWindowLongClickListener, OnInfoWindowCloseListener, OnMapAndViewReadyListener.OnGlobalLayoutAndMapReadyListener{ privatestaticfinalLatLngBRISBANE=newLatLng(-27.47093,153.0235); privatestaticfinalLatLngMELBOURNE=newLatLng(-37.81319,144.96298); privatestaticfinalLatLngDARWIN=newLatLng(-12.4634,130.8456); privatestaticfinalLatLngSYDNEY=newLatLng(-33.87365,151.20689); privatestaticfinalLatLngADELAIDE=newLatLng(-34.92873,138.59995); privatestaticfinalLatLngPERTH=newLatLng(-31.952854,115.857342); privatestaticfinalLatLngALICE_SPRINGS=newLatLng(-24.6980,133.8807); privatecom.example.common_ui.databinding.MarkerDemoBindingbinding; /** Demonstrates customizing the info window and/or its contents. */ class CustomInfoWindowAdapterimplementsInfoWindowAdapter{ // These are both viewgroups containing an ImageView with id "badge" and two TextViews with id // "title" and "snippet". privatefinalViewmWindow; privatefinalViewmContents; CustomInfoWindowAdapter(){ mWindow=getLayoutInflater().inflate(R.layout.custom_info_window,null); mContents=getLayoutInflater().inflate(R.layout.custom_info_contents,null); } @Override publicViewgetInfoWindow(Markermarker){ if(binding.customInfoWindowOptions.getCheckedRadioButtonId()!=R.id.custom_info_window){ // This means that getInfoContents will be called. returnnull; } render(marker,mWindow); returnmWindow; } @Override publicViewgetInfoContents(Markermarker){ if(binding.customInfoWindowOptions.getCheckedRadioButtonId()!=R.id.custom_info_contents){ // This means that the default info contents will be used. returnnull; } render(marker,mContents); returnmContents; } privatevoidrender(Markermarker,Viewview){ intbadge; // Use the equals() method on a Marker to check for equals. Do not use ==. if(marker.equals(mBrisbane)){ badge=R.drawable.badge_qld; }elseif(marker.equals(mAdelaide)){ badge=R.drawable.badge_sa; }elseif(marker.equals(mSydney)){ badge=R.drawable.badge_nsw; }elseif(marker.equals(mMelbourne)){ badge=R.drawable.badge_victoria; }elseif(marker.equals(mPerth)){ badge=R.drawable.badge_wa; }elseif(marker.equals(mDarwin1)){ badge=R.drawable.badge_nt; }elseif(marker.equals(mDarwin2)){ badge=R.drawable.badge_nt; }elseif(marker.equals(mDarwin3)){ badge=R.drawable.badge_nt; }elseif(marker.equals(mDarwin4)){ badge=R.drawable.badge_nt; }else{ // Passing 0 to setImageResource will clear the image view. badge=0; } ((ImageView)view.findViewById(R.id.badge)).setImageResource(badge); Stringtitle=marker.getTitle(); TextViewtitleUi=view.findViewById(R.id.title); if(title!=null){ // Spannable string allows us to edit the formatting of the text. SpannableStringtitleText=newSpannableString(title); titleText.setSpan(newForegroundColorSpan(Color.RED),0,titleText.length(),0); titleUi.setText(titleText); }else{ titleUi.setText(""); } Stringsnippet=marker.getSnippet(); TextViewsnippetUi=view.findViewById(R.id.snippet); if(snippet!=null && snippet.length() > 12){ SpannableStringsnippetText=newSpannableString(snippet); snippetText.setSpan(newForegroundColorSpan(Color.MAGENTA),0,10,0); snippetText.setSpan(newForegroundColorSpan(Color.BLUE),12,snippet.length(),0); snippetUi.setText(snippetText); }else{ snippetUi.setText(""); } } } privateGoogleMapmMap; privateMarkermPerth; privateMarkermSydney; privateMarkermBrisbane; privateMarkermAdelaide; privateMarkermMelbourne; privateMarkermDarwin1; privateMarkermDarwin2; privateMarkermDarwin3; privateMarkermDarwin4; /** * Keeps track of the last selected marker (though it may no longer be selected). This is * useful for refreshing the info window. */ privateMarkermLastSelectedMarker; privatefinalList<Marker>mMarkerRainbow=newArrayList<>(); privatefinalRandommRandom=newRandom(); @Override protectedvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); binding=com.example.common_ui.databinding.MarkerDemoBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); binding.rotationSeekBar.setMax(360); binding.rotationSeekBar.setOnSeekBarChangeListener(this); binding.customInfoWindowOptions.setOnCheckedChangeListener(newOnCheckedChangeListener(){ @Override publicvoidonCheckedChanged(RadioGroupgroup,intcheckedId){ if(mLastSelectedMarker!=null && mLastSelectedMarker.isInfoWindowShown()){ // Refresh the info window when the info window's content has changed. mLastSelectedMarker.showInfoWindow(); } } }); binding.clearMap.setOnClickListener(v->onClearMap()); binding.resetMap.setOnClickListener(v->onResetMap()); binding.flat.setOnClickListener(v->onToggleFlat()); SupportMapFragmentmapFragment= (SupportMapFragment)getSupportFragmentManager().findFragmentById(R.id.map); newOnMapAndViewReadyListener(mapFragment,this); applyInsets(binding.mapContainer); } @Override publicvoidonMapReady(GoogleMapmap){ mMap=map; // Hide the zoom controls as the button panel will cover it. mMap.getUiSettings().setZoomControlsEnabled(false); // Add lots of markers to the map. addMarkersToMap(); // Setting an info window adapter allows us to change the both the contents and look of the // info window. mMap.setInfoWindowAdapter(newCustomInfoWindowAdapter()); // Set listeners for marker events. See the bottom of this class for their behavior. mMap.setOnMarkerClickListener(this); mMap.setOnInfoWindowClickListener(this); mMap.setOnMarkerDragListener(this); mMap.setOnInfoWindowCloseListener(this); mMap.setOnInfoWindowLongClickListener(this); // Override the default content description on the view, for accessibility mode. // Ideally this string would be localised. mMap.setContentDescription("Map with lots of markers."); LatLngBoundsbounds=newLatLngBounds.Builder() .include(PERTH) .include(SYDNEY) .include(ADELAIDE) .include(BRISBANE) .include(MELBOURNE) .include(DARWIN) .build(); mMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds,50)); } privatevoidaddMarkersToMap(){ // Uses a colored icon. mBrisbane=mMap.addMarker(newMarkerOptions() .position(BRISBANE) .title("Brisbane") .snippet("Population: 2,074,200") .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_AZURE))); // Uses a custom icon with the info window popping out of the center of the icon. mSydney=mMap.addMarker(newMarkerOptions() .position(SYDNEY) .title("Sydney") .snippet("Population: 4,627,300") .icon(BitmapDescriptorFactory.fromResource(R.drawable.arrow)) .infoWindowAnchor(0.5f,0.5f)); // Creates a draggable marker. Long press to drag. mMelbourne=mMap.addMarker(newMarkerOptions() .position(MELBOURNE) .title("Melbourne") .snippet("Population: 4,137,400") .draggable(true)); // Place four markers on top of each other with differing z-indexes. mDarwin1=mMap.addMarker(newMarkerOptions() .position(DARWIN) .title("Darwin Marker 1") .snippet("z-index 1") .zIndex(1)); mDarwin2=mMap.addMarker(newMarkerOptions() .position(DARWIN) .title("Darwin Marker 2") .snippet("z-index 2") .zIndex(2)); mDarwin3=mMap.addMarker(newMarkerOptions() .position(DARWIN) .title("Darwin Marker 3") .snippet("z-index 3") .zIndex(3)); mDarwin4=mMap.addMarker(newMarkerOptions() .position(DARWIN) .title("Darwin Marker 4") .snippet("z-index 4") .zIndex(4)); // A few more markers for good measure. mPerth=mMap.addMarker(newMarkerOptions() .position(PERTH) .title("Perth") .snippet("Population: 1,738,800")); mAdelaide=mMap.addMarker(newMarkerOptions() .position(ADELAIDE) .title("Adelaide") .snippet("Population: 1,213,000")); // Vector drawable resource as a marker icon. mMap.addMarker(newMarkerOptions() .position(ALICE_SPRINGS) .icon(vectorToBitmap(R.drawable.ic_android,Color.parseColor("#A4C639"))) .title("Alice Springs")); // Creates a marker rainbow demonstrating how to create default marker icons of different // hues (colors). floatrotation=binding.rotationSeekBar.getProgress(); booleanflat=binding.flat.isChecked(); intnumMarkersInRainbow=12; for(inti=0;i < numMarkersInRainbow;i++){ Markermarker=mMap.addMarker(newMarkerOptions() .position(newLatLng( -30+10*Math.sin(i*Math.PI/(numMarkersInRainbow-1)), 135-10*Math.cos(i*Math.PI/(numMarkersInRainbow-1)))) .title("Marker "+i) .icon(BitmapDescriptorFactory.defaultMarker(i*360/numMarkersInRainbow)) .flat(flat) .rotation(rotation)); mMarkerRainbow.add(marker); } } /** * Demonstrates converting a {@link Drawable} to a {@link BitmapDescriptor}, * for use as a marker icon. */ privateBitmapDescriptorvectorToBitmap(@DrawableResintid,@ColorIntintcolor){ DrawablevectorDrawable=ResourcesCompat.getDrawable(getResources(),id,null); Bitmapbitmap=Bitmap.createBitmap(vectorDrawable.getIntrinsicWidth(), vectorDrawable.getIntrinsicHeight(),Bitmap.Config.ARGB_8888); Canvascanvas=newCanvas(bitmap); vectorDrawable.setBounds(0,0,canvas.getWidth(),canvas.getHeight()); DrawableCompat.setTint(vectorDrawable,color); vectorDrawable.draw(canvas); returnBitmapDescriptorFactory.fromBitmap(bitmap); } privatebooleancheckReady(){ if(mMap==null){ Toast.makeText(this,R.string.map_not_ready,Toast.LENGTH_SHORT).show(); returnfalse; } returntrue; } privatevoidonClearMap(){ if(!checkReady()){ return; } mMap.clear(); } privatevoidonResetMap(){ if(!checkReady()){ return; } // Clear the map because we don't want duplicates of the markers. mMap.clear(); addMarkersToMap(); } privatevoidonToggleFlat(){ if(!checkReady()){ return; } booleanflat=binding.flat.isChecked(); for(Markermarker:mMarkerRainbow){ marker.setFlat(flat); } } @Override publicvoidonProgressChanged(SeekBarseekBar,intprogress,booleanfromUser){ if(!checkReady()){ return; } floatrotation=seekBar.getProgress(); for(Markermarker:mMarkerRainbow){ marker.setRotation(rotation); } } @Override publicvoidonStartTrackingTouch(SeekBarseekBar){ // Do nothing. } @Override publicvoidonStopTrackingTouch(SeekBarseekBar){ // Do nothing. } // // Marker related listeners. // @Override publicbooleanonMarkerClick(finalMarkermarker){ if(marker.equals(mPerth)){ // This causes the marker at Perth to bounce into position when it is clicked. finalHandlerhandler=newHandler(Looper.getMainLooper()); finallongstart=SystemClock.uptimeMillis(); finallongduration=1500; finalInterpolatorinterpolator=newBounceInterpolator(); handler.post(newRunnable(){ @Override publicvoidrun(){ longelapsed=SystemClock.uptimeMillis()-start; floatt=Math.max( 1-interpolator.getInterpolation((float)elapsed/duration),0); marker.setAnchor(0.5f,1.0f+2*t); if(t > 0.0){ // Post again 16ms later. handler.postDelayed(this,16); } } }); }elseif(marker.equals(mAdelaide)){ // This causes the marker at Adelaide to change color and alpha. marker.setIcon(BitmapDescriptorFactory.defaultMarker(mRandom.nextFloat()*360)); marker.setAlpha(mRandom.nextFloat()); } // Markers have a z-index that is settable and gettable. floatzIndex=marker.getZIndex()+1.0f; marker.setZIndex(zIndex); Toast.makeText(this,marker.getTitle()+" z-index set to "+zIndex, Toast.LENGTH_SHORT).show(); mLastSelectedMarker=marker; // We return false to indicate that we have not consumed the event and that we wish // for the default behavior to occur (which is for the camera to move such that the // marker is centered and for the marker's info window to open, if it has one). returnfalse; } @Override publicvoidonInfoWindowClick(Markermarker){ Toast.makeText(this,"Click Info Window",Toast.LENGTH_SHORT).show(); } @Override publicvoidonInfoWindowClose(Markermarker){ //Toast.makeText(this, "Close Info Window", Toast.LENGTH_SHORT).show(); } @Override publicvoidonInfoWindowLongClick(Markermarker){ Toast.makeText(this,"Info Window long click",Toast.LENGTH_SHORT).show(); } @Override publicvoidonMarkerDragStart(Markermarker){ binding.topText.setText(R.string.on_marker_drag_start); } @Override publicvoidonMarkerDragEnd(Markermarker){ binding.topText.setText(R.string.on_marker_drag_end); } @Override publicvoidonMarkerDrag(Markermarker){ binding.topText.setText(getString(R.string.on_marker_drag,marker.getPosition().latitude,marker.getPosition().longitude)); } }
Clone and run the samples
Git is required to run this sample locally. The following command clones the sample application repository.
git clone git@github.com:googlemaps-samples/android-samples.git
Import the sample project into Android Studio:
- In Android Studio, select File> New> Import Project.
Go to the location where you saved the repository and select the project directory for Kotlin or Java:
- Kotlin:
PATH-REPO/android-samples/ApiDemos/kotlin - Java:
PATH-REPO/android-samples/ApiDemos/java
- Kotlin:
- Select Open. Android Studio builds your project, using the Gradle build tool.
- Create a blank
secrets.propertiesfile in the same directory as your project'slocal.propertiesfile. For more information about this file, see Add your API key to the project. - Get an API key from your project with the Maps SDK for Android enabled.
Add the following string to
secrets.properties, replacing YOUR_API_KEY with the value of your API key:MAPS_API_KEY=YOUR_API_KEY- Run the app.