Events
Stay organized with collections
Save and categorize content based on your preferences.
Page Summary
-
The Maps SDK for Android allows developers to respond to map interactions like clicks, camera movements, and indoor map state changes using events and listeners.
-
Camera movements can be programmatically controlled and tracked, with listeners providing information about the start, progress, and end of movements.
-
Points of Interest, markers, info windows, shapes, overlays, and the My Location feature all offer event handling capabilities for customized interactions.
-
Developers can handle click events on various map elements, with prioritization given to markers within clusters and then other clickable overlays based on their z-index.
-
Indoor maps provide events for detecting changes in focused buildings and active levels, allowing for tailored content and interactions within indoor environments.
Using the Maps SDK for Android, you can listen to events on the map.
Code samples
The ApiDemos repository on GitHub includes samples that demonstrates events and listeners:
Kotlin
- EventsDemoActivity: Map click and camera change events
- CameraDemoActivity: Camera change events
- CircleDemoActivity: Marker click and drag events
- GroundOverlayDemoActivity: Ground overlay click events
- IndoorDemoActivity: Indoor map events
- MarkerDemoActivity: Marker and info window events
- PolygonDemoActivity: Polygon events
Java
- EventsDemoActivity: Map click and camera change events
- CameraDemoActivity: Camera change events
- CircleDemoActivity: Marker click and drag events
- GroundOverlayDemoActivity: Ground overlay click events
- IndoorDemoActivity: Indoor map events
- MarkerDemoActivity: Marker and info window events
- PolygonDemoActivity: Polygon events
Map click / long click events
If you want to respond to a user tapping on a point on the map, you can use an
OnMapClickListener which you can set on the map by
calling GoogleMap.setOnMapClickListener(OnMapClickListener). When a user
clicks (taps) somewhere on the map, you will receive an onMapClick(LatLng)
event that indicates the location on the map that the user clicked. Note that
if you need the corresponding location on the screen (in pixels), you can
obtain a Projection from the map which allows you to convert
between latitude/longitude coordinates and screen pixel coordinates.
You can also listen for long click events with an
OnMapLongClickListener which you can set on the
map by calling GoogleMap.setOnMapLongClickListener(OnMapLongClickListener).
This listener behaves similarly to the click listener and will be notified on
long click events with an onMapLongClick(LatLng) callback.
Disabling click events in lite mode
To disable click events on a map in lite mode, call setClickable()
on the view that contains the MapView or MapFragment. This is useful,
for example, when displaying a map or maps in a list view, where you want
the click event to invoke an action unrelated to the map.
The option to disable click events is available in lite mode only. Disabling click events will also make markers non-clickable. It will not affect other controls on the map.
For a MapView:
Kotlin
valmapView=findViewById<MapView>(R.id.mapView) mapView.isClickable=false
Java
MapViewmapView=findViewById(R.id.mapView); mapView.setClickable(false);
For a MapFragment:
Kotlin
valmapFragment=supportFragmentManager .findFragmentById(R.id.map)asSupportMapFragment valview=mapFragment.view view?.isClickable=false
Java
SupportMapFragmentmapFragment=(SupportMapFragment)getSupportFragmentManager() .findFragmentById(R.id.map); Viewview=mapFragment.getView(); view.setClickable(false);
Camera change events
The map view is modeled as a camera looking down on a flat plane. You can change the properties of the camera to affect the zoom level, view port and perspective of the map. See the guide to the camera. Users can also affect the camera by making gestures.
Using camera change listeners, you can keep track of camera movements. Your app can receive notifications for camera motion start, ongoing, and end events. You can also see why the camera is moving, whether it's caused by user gestures, built-in API animations or developer-controlled movements.
The following sample illustrates all the available camera event listeners:
Kotlin
/*
* Copyright 2018 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
packagecom.example.kotlindemos
importandroid.graphics.Color
importandroid.os.Bundle
importandroid.util.Log
importandroid.view.View
importandroid.widget.CompoundButton
importandroid.widget.SeekBar
importandroid.widget.Toast
importcom.example.common_ui.R
importcom.google.android.gms.maps.CameraUpdate
importcom.google.android.gms.maps.CameraUpdateFactory
importcom.google.android.gms.maps.GoogleMap
importcom.google.android.gms.maps.GoogleMap.CancelableCallback
importcom.google.android.gms.maps.GoogleMap.OnCameraIdleListener
importcom.google.android.gms.maps.GoogleMap.OnCameraMoveCanceledListener
importcom.google.android.gms.maps.GoogleMap.OnCameraMoveListener
importcom.google.android.gms.maps.GoogleMap.OnCameraMoveStartedListener
importcom.google.android.gms.maps.OnMapReadyCallback
importcom.google.android.gms.maps.SupportMapFragment
importcom.google.android.gms.maps.model.CameraPosition
importcom.google.android.gms.maps.model.LatLng
importcom.example.common_ui.databinding.CameraDemoBinding
importcom.google.android.gms.maps.model.PolylineOptions
/**
* This shows how to change the camera position for the map.
*/
classCameraDemoActivity:
SamplesBaseActivity(),
OnCameraMoveStartedListener,
OnCameraMoveListener,
OnCameraMoveCanceledListener,
OnCameraIdleListener,
OnMapReadyCallback{
/**
* The amount by which to scroll the camera. Note that this amount is in raw pixels, not dp
* (density-independent pixels).
*/
privatevalSCROLL_BY_PX=100
privatevalTAG=CameraDemoActivity::class.java.name
privatevalsydneyLatLng=LatLng(-33.87365,151.20689)
privatevalbondiLocation:CameraPosition=CameraPosition.Builder()
.target(LatLng(-33.891614,151.276417))
.zoom(15.5f)
.bearing(300f)
.tilt(50f)
.build()
privatevalsydneyLocation:CameraPosition=CameraPosition.Builder().
target(LatLng(-33.87365,151.20689))
.zoom(15.5f)
.bearing(0f)
.tilt(25f)
.build()
privatelateinitvarmap:GoogleMap
privatelateinitvaranimateToggle:CompoundButton
privatelateinitvarcustomDurationToggle:CompoundButton
privatelateinitvarcustomDurationBar:SeekBar
privatevarcurrPolylineOptions:PolylineOptions? =null
privatevarisCanceled=false
privatelateinitvarbinding:CameraDemoBinding
overridefunonCreate(savedInstanceState:Bundle?){
super.onCreate(savedInstanceState)
binding=CameraDemoBinding.inflate(layoutInflater)
setContentView(binding.root)
animateToggle=binding.animate
customDurationToggle=binding.durationToggle
customDurationBar=binding.durationBar
updateEnabledState()
valmapFragment=supportFragmentManager.findFragmentById(R.id.map)asSupportMapFragment
mapFragment.getMapAsync(this)
applyInsets(binding.mapContainer)
binding.bondi.setOnClickListener(this::onGoToBondi)
binding.sydney.setOnClickListener(this::onGoToSydney)
binding.stopAnimation.setOnClickListener(this::onStopAnimation)
binding.animate.setOnClickListener(this::onToggleAnimate)
binding.scrollLeft.setOnClickListener(this::onScrollLeft)
binding.scrollUp.setOnClickListener(this::onScrollUp)
binding.scrollDown.setOnClickListener(this::onScrollDown)
binding.scrollRight.setOnClickListener(this::onScrollRight)
binding.zoomIn.setOnClickListener(this::onZoomIn)
binding.zoomOut.setOnClickListener(this::onZoomOut)
binding.tiltMore.setOnClickListener(this::onTiltMore)
binding.tiltLess.setOnClickListener(this::onTiltLess)
binding.durationToggle.setOnClickListener(this::onToggleCustomDuration)
}
overridefunonResume(){
super.onResume()
updateEnabledState()
}
overridefunonMapReady(googleMap:GoogleMap){
map=googleMap
// return early if the map was not initialised properly
with(googleMap){
setOnCameraIdleListener(this@CameraDemoActivity)
setOnCameraMoveStartedListener(this@CameraDemoActivity)
setOnCameraMoveListener(this@CameraDemoActivity)
setOnCameraMoveCanceledListener(this@CameraDemoActivity)
// We will provide our own zoom controls.
uiSettings.isZoomControlsEnabled=false
uiSettings.isMyLocationButtonEnabled=true
// Show Sydney
moveCamera(CameraUpdateFactory.newLatLngZoom(sydneyLatLng,10f))
}
}
/**
* When the map is not ready the CameraUpdateFactory cannot be used. This should be used to wrap
* all entry points that call methods on the Google Maps API.
*
* @param stuffToDo the code to be executed if the map is initialised
*/
privatefuncheckReadyThen(stuffToDo:()->Unit){
if(!::map.isInitialized){
Toast.makeText(this,R.string.map_not_ready,Toast.LENGTH_SHORT).show()
}else{
stuffToDo()
}
}
/**
* Called when the Go To Bondi button is clicked.
*/
@Suppress("UNUSED_PARAMETER")
funonGoToBondi(view:View){
checkReadyThen{
changeCamera(CameraUpdateFactory.newCameraPosition(bondiLocation))
}
}
/**
* Called when the Animate To Sydney button is clicked.
*/
@Suppress("UNUSED_PARAMETER")
funonGoToSydney(view:View){
checkReadyThen{
changeCamera(CameraUpdateFactory.newCameraPosition(sydneyLocation),
object:CancelableCallback{
overridefunonFinish(){
Toast.makeText(baseContext,"Animation to Sydney complete",
Toast.LENGTH_SHORT).show()
}
overridefunonCancel(){
Toast.makeText(baseContext,"Animation to Sydney canceled",
Toast.LENGTH_SHORT).show()
}
})
}
}
/**
* Called when the stop button is clicked.
*/
@Suppress("UNUSED_PARAMETER")
funonStopAnimation(view:View)=checkReadyThen{map.stopAnimation()}
/**
* Called when the zoom in button (the one with the +) is clicked.
*/
@Suppress("UNUSED_PARAMETER")
funonZoomIn(view:View)=checkReadyThen{changeCamera(CameraUpdateFactory.zoomIn())}
/**
* Called when the zoom out button (the one with the -) is clicked.
*/
@Suppress("UNUSED_PARAMETER")
funonZoomOut(view:View)=checkReadyThen{changeCamera(CameraUpdateFactory.zoomOut())}
/**
* Called when the tilt more button (the one with the /) is clicked.
*/
@Suppress("UNUSED_PARAMETER")
funonTiltMore(view:View){
checkReadyThen{
valnewTilt=Math.min(map.cameraPosition.tilt+10,90F)
valcameraPosition=CameraPosition.Builder(map.cameraPosition).tilt(newTilt).build()
changeCamera(CameraUpdateFactory.newCameraPosition(cameraPosition))
}
}
/**
* Called when the tilt less button (the one with the \) is clicked.
*/
@Suppress("UNUSED_PARAMETER")
funonTiltLess(view:View){
checkReadyThen{
valnewTilt=Math.max(map.cameraPosition.tilt-10,0F)
valcameraPosition=CameraPosition.Builder(map.cameraPosition).tilt(newTilt).build()
changeCamera(CameraUpdateFactory.newCameraPosition(cameraPosition))
}
}
/**
* Called when the left arrow button is clicked. This causes the camera to move to the left
*/
@Suppress("UNUSED_PARAMETER")
funonScrollLeft(view:View){
checkReadyThen{
changeCamera(CameraUpdateFactory.scrollBy((-SCROLL_BY_PX).toFloat(),0f))
}
}
/**
* Called when the right arrow button is clicked. This causes the camera to move to the right.
*/
@Suppress("UNUSED_PARAMETER")
funonScrollRight(view:View){
checkReadyThen{
changeCamera(CameraUpdateFactory.scrollBy(SCROLL_BY_PX.toFloat(),0f))
}
}
/**
* Called when the up arrow button is clicked. The causes the camera to move up.
*/
@Suppress("UNUSED_PARAMETER")
funonScrollUp(view:View){
checkReadyThen{
changeCamera(CameraUpdateFactory.scrollBy(0f,(-SCROLL_BY_PX).toFloat()))
}
}
/**
* Called when the down arrow button is clicked. This causes the camera to move down.
*/
@Suppress("UNUSED_PARAMETER")
funonScrollDown(view:View){
checkReadyThen{
changeCamera(CameraUpdateFactory.scrollBy(0f,SCROLL_BY_PX.toFloat()))
}
}
/**
* Called when the animate button is toggled
*/
@Suppress("UNUSED_PARAMETER")
funonToggleAnimate(view:View)=updateEnabledState()
/**
* Called when the custom duration checkbox is toggled
*/
@Suppress("UNUSED_PARAMETER")
funonToggleCustomDuration(view:View)=updateEnabledState()
/**
* Update the enabled state of the custom duration controls.
*/
privatefunupdateEnabledState(){
customDurationToggle.isEnabled=animateToggle.isChecked
customDurationBar.isEnabled=animateToggle.isChecked && customDurationToggle.isChecked
}
/**
* Change the camera position by moving or animating the camera depending on the state of the
* animate toggle button.
*/
privatefunchangeCamera(update:CameraUpdate,callback:CancelableCallback? =null){
if(animateToggle.isChecked){
if(customDurationToggle.isChecked){
// The duration must be strictly positive so we make it at least 1.
map.animateCamera(update,Math.max(customDurationBar.progress,1),callback)
}else{
map.animateCamera(update,callback)
}
}else{
map.moveCamera(update)
}
}
overridefunonCameraMoveStarted(reason:Int){
if(!isCanceled)map.clear()
varreasonText="UNKNOWN_REASON"
currPolylineOptions=PolylineOptions().width(5f)
when(reason){
OnCameraMoveStartedListener.REASON_GESTURE->{
currPolylineOptions?.color(Color.BLUE)
reasonText="GESTURE"
}
OnCameraMoveStartedListener.REASON_API_ANIMATION->{
currPolylineOptions?.color(Color.RED)
reasonText="API_ANIMATION"
}
OnCameraMoveStartedListener.REASON_DEVELOPER_ANIMATION->{
currPolylineOptions?.color(Color.GREEN)
reasonText="DEVELOPER_ANIMATION"
}
}
Log.d(TAG,"onCameraMoveStarted($reasonText)")
addCameraTargetToPath()
}
/**
* Ensures that currPolyLine options is not null before accessing it
*
* @param stuffToDo the code to be executed if currPolylineOptions is not null
*/
privatefuncheckPolylineThen(stuffToDo:()->Unit){
if(currPolylineOptions!=null)stuffToDo()
}
overridefunonCameraMove(){
Log.d(TAG,"onCameraMove")
// When the camera is moving, add its target to the current path we'll draw on the map.
checkPolylineThen{addCameraTargetToPath()}
}
overridefunonCameraMoveCanceled(){
// When the camera stops moving, add its target to the current path, and draw it on the map.
checkPolylineThen{
addCameraTargetToPath()
map.addPolyline(currPolylineOptions!!)
}
isCanceled=true// Set to clear the map when dragging starts again.
currPolylineOptions=null
Log.d(TAG,"onCameraMoveCancelled")
}
overridefunonCameraIdle(){
checkPolylineThen{
addCameraTargetToPath()
map.addPolyline(currPolylineOptions!!)
}
currPolylineOptions=null
isCanceled=false// Set to *not* clear the map when dragging starts again.
Log.d(TAG,"onCameraIdle")
}
privatefunaddCameraTargetToPath(){
currPolylineOptions?.add(map.cameraPosition.target)
}
}
Java
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
packagecom.example.mapdemo;
importandroid.graphics.Color;
importandroid.os.Bundle;
importandroid.util.Log;
importandroid.view.View;
importandroid.widget.CompoundButton;
importandroid.widget.SeekBar;
importandroid.widget.Toast;
importandroidx.appcompat.app.AppCompatActivity;
importcom.google.android.gms.maps.CameraUpdate;
importcom.google.android.gms.maps.CameraUpdateFactory;
importcom.google.android.gms.maps.GoogleMap;
importcom.google.android.gms.maps.GoogleMap.CancelableCallback;
importcom.google.android.gms.maps.GoogleMap.OnCameraIdleListener;
importcom.google.android.gms.maps.GoogleMap.OnCameraMoveCanceledListener;
importcom.google.android.gms.maps.GoogleMap.OnCameraMoveListener;
importcom.google.android.gms.maps.GoogleMap.OnCameraMoveStartedListener;
importcom.google.android.gms.maps.OnMapReadyCallback;
importcom.google.android.gms.maps.SupportMapFragment;
importcom.google.android.gms.maps.model.CameraPosition;
importcom.google.android.gms.maps.model.LatLng;
importcom.example.common_ui.databinding.CameraDemoBinding;
importcom.google.android.gms.maps.model.PolylineOptions;
/**
* This shows how to change the camera position for the map.
*/
publicclass CameraDemoActivityextendsSamplesBaseActivityimplements
OnCameraMoveStartedListener,
OnCameraMoveListener,
OnCameraMoveCanceledListener,
OnCameraIdleListener,
OnMapReadyCallback{
privatestaticfinalStringTAG=CameraDemoActivity.class.getName();
/**
* The amount by which to scroll the camera. Note that this amount is in raw pixels, not dp
* (density-independent pixels).
*/
privatestaticfinalintSCROLL_BY_PX=100;
publicstaticfinalCameraPositionBONDI=
newCameraPosition.Builder().target(newLatLng(-33.891614,151.276417))
.zoom(15.5f)
.bearing(300)
.tilt(50)
.build();
publicstaticfinalCameraPositionSYDNEY=
newCameraPosition.Builder().target(newLatLng(-33.87365,151.20689))
.zoom(15.5f)
.bearing(0)
.tilt(25)
.build();
privateGoogleMapmap;
privateCompoundButtonanimateToggle;
privateCompoundButtoncustomDurationToggle;
privateSeekBarcustomDurationBar;
privatePolylineOptionscurrPolylineOptions;
privatebooleanisCanceled=false;
privateCameraDemoBindingbinding;
@Override
protectedvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
binding=CameraDemoBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
animateToggle=binding.animate;
customDurationToggle=binding.durationToggle;
customDurationBar=binding.durationBar;
updateEnabledState();
SupportMapFragmentmapFragment=
(SupportMapFragment)getSupportFragmentManager().findFragmentById(com.example.common_ui.R.id.map);
mapFragment.getMapAsync(this);
applyInsets(binding.mapContainer);
binding.bondi.setOnClickListener(this::onGoToBondi);
binding.sydney.setOnClickListener(this::onGoToSydney);
binding.stopAnimation.setOnClickListener(this::onStopAnimation);
binding.animate.setOnClickListener(this::onToggleAnimate);
binding.scrollLeft.setOnClickListener(this::onScrollLeft);
binding.scrollUp.setOnClickListener(this::onScrollUp);
binding.scrollDown.setOnClickListener(this::onScrollDown);
binding.scrollRight.setOnClickListener(this::onScrollRight);
binding.zoomIn.setOnClickListener(this::onZoomIn);
binding.zoomOut.setOnClickListener(this::onZoomOut);
binding.tiltMore.setOnClickListener(this::onTiltMore);
binding.tiltLess.setOnClickListener(this::onTiltLess);
binding.durationToggle.setOnClickListener(this::onToggleCustomDuration);
}
@Override
protectedvoidonResume(){
super.onResume();
updateEnabledState();
}
@Override
publicvoidonMapReady(GoogleMapgoogleMap){
map=googleMap;
map.setOnCameraIdleListener(this);
map.setOnCameraMoveStartedListener(this);
map.setOnCameraMoveListener(this);
map.setOnCameraMoveCanceledListener(this);
// We will provide our own zoom controls.
map.getUiSettings().setZoomControlsEnabled(false);
map.getUiSettings().setMyLocationButtonEnabled(true);
// Show Sydney
map.moveCamera(CameraUpdateFactory.newLatLngZoom(newLatLng(-33.87365,151.20689),10));
}
publicGoogleMapgetMap(){
returnmap;
}
/**
* When the map is not ready the CameraUpdateFactory cannot be used. This should be called on
* all entry points that call methods on the Google Maps API.
*/
privatebooleancheckReady(){
if(map==null){
Toast.makeText(this,com.example.common_ui.R.string.map_not_ready,Toast.LENGTH_SHORT).show();
returnfalse;
}
returntrue;
}
/**
* Called when the Go To Bondi button is clicked.
*/
publicvoidonGoToBondi(Viewview){
if(!checkReady()){
return;
}
changeCamera(CameraUpdateFactory.newCameraPosition(BONDI));
}
/**
* Called when the Animate To Sydney button is clicked.
*/
publicvoidonGoToSydney(Viewview){
if(!checkReady()){
return;
}
changeCamera(CameraUpdateFactory.newCameraPosition(SYDNEY),newCancelableCallback(){
@Override
publicvoidonFinish(){
Toast.makeText(getBaseContext(),"Animation to Sydney complete",Toast.LENGTH_SHORT)
.show();
}
@Override
publicvoidonCancel(){
Toast.makeText(getBaseContext(),"Animation to Sydney canceled",Toast.LENGTH_SHORT)
.show();
}
});
}
/**
* Called when the stop button is clicked.
*/
publicvoidonStopAnimation(Viewview){
if(!checkReady()){
return;
}
map.stopAnimation();
}
/**
* Called when the zoom in button (the one with the +) is clicked.
*/
publicvoidonZoomIn(Viewview){
if(!checkReady()){
return;
}
changeCamera(CameraUpdateFactory.zoomIn());
}
/**
* Called when the zoom out button (the one with the -) is clicked.
*/
publicvoidonZoomOut(Viewview){
if(!checkReady()){
return;
}
changeCamera(CameraUpdateFactory.zoomOut());
}
/**
* Called when the tilt more button (the one with the /) is clicked.
*/
publicvoidonTiltMore(Viewview){
if(!checkReady()){
return;
}
CameraPositioncurrentCameraPosition=map.getCameraPosition();
floatcurrentTilt=currentCameraPosition.tilt;
floatnewTilt=currentTilt+10;
newTilt=(newTilt > 90)?90:newTilt;
CameraPositioncameraPosition=newCameraPosition.Builder(currentCameraPosition)
.tilt(newTilt).build();
changeCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
}
/**
* Called when the tilt less button (the one with the \) is clicked.
*/
publicvoidonTiltLess(Viewview){
if(!checkReady()){
return;
}
CameraPositioncurrentCameraPosition=map.getCameraPosition();
floatcurrentTilt=currentCameraPosition.tilt;
floatnewTilt=currentTilt-10;
newTilt=(newTilt > 0)?newTilt:0;
CameraPositioncameraPosition=newCameraPosition.Builder(currentCameraPosition)
.tilt(newTilt).build();
changeCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
}
/**
* Called when the left arrow button is clicked. This causes the camera to move to the left
*/
publicvoidonScrollLeft(Viewview){
if(!checkReady()){
return;
}
changeCamera(CameraUpdateFactory.scrollBy(-SCROLL_BY_PX,0));
}
/**
* Called when the right arrow button is clicked. This causes the camera to move to the right.
*/
publicvoidonScrollRight(Viewview){
if(!checkReady()){
return;
}
changeCamera(CameraUpdateFactory.scrollBy(SCROLL_BY_PX,0));
}
/**
* Called when the up arrow button is clicked. The causes the camera to move up.
*/
publicvoidonScrollUp(Viewview){
if(!checkReady()){
return;
}
changeCamera(CameraUpdateFactory.scrollBy(0,-SCROLL_BY_PX));
}
/**
* Called when the down arrow button is clicked. This causes the camera to move down.
*/
publicvoidonScrollDown(Viewview){
if(!checkReady()){
return;
}
changeCamera(CameraUpdateFactory.scrollBy(0,SCROLL_BY_PX));
}
/**
* Called when the animate button is toggled
*/
publicvoidonToggleAnimate(Viewview){
updateEnabledState();
}
/**
* Called when the custom duration checkbox is toggled
*/
publicvoidonToggleCustomDuration(Viewview){
updateEnabledState();
}
/**
* Update the enabled state of the custom duration controls.
*/
privatevoidupdateEnabledState(){
customDurationToggle.setEnabled(animateToggle.isChecked());
customDurationBar
.setEnabled(animateToggle.isChecked() && customDurationToggle.isChecked());
}
privatevoidchangeCamera(CameraUpdateupdate){
changeCamera(update,null);
}
/**
* Change the camera position by moving or animating the camera depending on the state of the
* animate toggle button.
*/
privatevoidchangeCamera(CameraUpdateupdate,CancelableCallbackcallback){
if(animateToggle.isChecked()){
if(customDurationToggle.isChecked()){
intduration=customDurationBar.getProgress();
// The duration must be strictly positive so we make it at least 1.
map.animateCamera(update,Math.max(duration,1),callback);
}else{
map.animateCamera(update,callback);
}
}else{
map.moveCamera(update);
}
}
@Override
publicvoidonCameraMoveStarted(intreason){
if(!isCanceled){
map.clear();
}
StringreasonText="UNKNOWN_REASON";
currPolylineOptions=newPolylineOptions().width(5);
switch(reason){
caseOnCameraMoveStartedListener.REASON_GESTURE:
currPolylineOptions.color(Color.BLUE);
reasonText="GESTURE";
break;
caseOnCameraMoveStartedListener.REASON_API_ANIMATION:
currPolylineOptions.color(Color.RED);
reasonText="API_ANIMATION";
break;
caseOnCameraMoveStartedListener.REASON_DEVELOPER_ANIMATION:
currPolylineOptions.color(Color.GREEN);
reasonText="DEVELOPER_ANIMATION";
break;
}
Log.d(TAG,"onCameraMoveStarted("+reasonText+")");
addCameraTargetToPath();
}
@Override
publicvoidonCameraMove(){
// When the camera is moving, add its target to the current path we'll draw on the map.
if(currPolylineOptions!=null){
addCameraTargetToPath();
}
Log.d(TAG,"onCameraMove");
}
@Override
publicvoidonCameraMoveCanceled(){
// When the camera stops moving, add its target to the current path, and draw it on the map.
if(currPolylineOptions!=null){
addCameraTargetToPath();
map.addPolyline(currPolylineOptions);
}
isCanceled=true;// Set to clear the map when dragging starts again.
currPolylineOptions=null;
Log.d(TAG,"onCameraMoveCancelled");
}
@Override
publicvoidonCameraIdle(){
if(currPolylineOptions!=null){
addCameraTargetToPath();
map.addPolyline(currPolylineOptions);
}
currPolylineOptions=null;
isCanceled=false;// Set to *not* clear the map when dragging starts again.
Log.d(TAG,"onCameraIdle");
}
privatevoidaddCameraTargetToPath(){
LatLngtarget=map.getCameraPosition().target;
currPolylineOptions.add(target);
}
}
The following camera listeners are available:
The
onCameraMoveStarted()callback of theOnCameraMoveStartedListeneris invoked when the camera starts moving. The callback method receives areasonfor the camera motion. The reason can be one of the following:REASON_GESTUREindicates that the camera moved in response to a user's gesture on the map, such as panning, tilting, pinching to zoom, or rotating the map.REASON_API_ANIMATIONindicates that the API has moved the camera in response to a non-gesture user action, such as tapping the zoom button, tapping the My Location button, or clicking a marker.REASON_DEVELOPER_ANIMATIONindicates that your app has initiated the camera movement.
The
onCameraMove()callback of theOnCameraMoveListeneris invoked multiple times while the camera is moving or the user is interacting with the touch screen. As a guide to how often the callback is invoked, it's useful to know that the API invokes the callback once per frame. Note, however, that this callback is invoked asynchronously and is therefore out of synch with what is visible on the screen. Also note that it's possible for the camera position to remain unchanged between oneonCameraMove()callback and the next.The
OnCameraIdle()callback of theOnCameraIdleListeneris invoked when the camera stops moving and the user has stopped interacting with the map.The
OnCameraMoveCanceled()callback of theOnCameraMoveCanceledListeneris invoked when the current camera movement has been interrupted. Immediately after theOnCameraMoveCanceled()callback, theonCameraMoveStarted()callback is invoked with the newreason.If your app explicitly calls
GoogleMap.stopAnimation(), theOnCameraMoveCanceled()callback is invoked, but theonCameraMoveStarted()callback is not invoked.
To set a listener on the map, call the relevant set-listener method.
For example, to request a callback from the OnCameraMoveStartedListener, call
GoogleMap.setOnCameraMoveStartedListener().
You can get the camera's target (latitude/longitude), zoom, bearing and tilt
from the CameraPosition. See the guide to
camera position for details about these properties.
Events on businesses and other points of interest
By default, points of interest (POIs) appear on the base map along with their corresponding icons. POIs include parks, schools, government buildings, and more, as well as business POIs such as shops, restaurants, and hotels.
You can respond to click events on a POI. See the guide to businesses and other points of interest.
Indoor map events
You can use events to find and customize the active level of an indoor map. Use
the OnIndoorStateChangeListener
interface to set a listener to be called when
either a new building is focused or a new level is activated in a building.
Get the building that is currently in focus by calling
GoogleMap.getFocusedBuilding().
Centering the map on a specific lat/long will
generally give you the building at that lat/long, but this is not guaranteed.
You can then find the currently active level by calling
IndoorBuilding.getActiveLevelIndex().
Kotlin
map.focusedBuilding?.let{building:IndoorBuilding-> valactiveLevelIndex=building.activeLevelIndex valactiveLevel=building.levels[activeLevelIndex] }
Java
IndoorBuildingbuilding=map.getFocusedBuilding(); if(building!=null){ intactiveLevelIndex=building.getActiveLevelIndex(); IndoorLevelactiveLevel=building.getLevels().get(activeLevelIndex); }
This is useful if you want to show custom markup for the active level, such as markers, ground overlays, tile overlays, polygons, polylines, and other shapes.
Hint: To go back to street level, get the default level via
IndoorBuilding.getDefaultLevelIndex(), and set it as the active level via
IndoorLevel.activate().
Marker and info window events
You can listen and respond to marker events, including marker click and drag
events, by setting the corresponding listener on the GoogleMap object to which
the marker belongs. See the guide to marker events.
You can also listen to events on info windows.
Shape and overlay events
You can listen and respond to click events on polylines, polygons, circles, and ground overlays.
Location events
Your app can respond to the following events related to the My Location layer:
- If the user clicks the My Location button, your app receives an
onMyLocationButtonClick()callback from theGoogleMap.OnMyLocationButtonClickListener. - If the user clicks the My Location blue dot, your app receives an
onMyLocationClick()callback from theGoogleMap.OnMyLocationClickListener.
For details, see the guide to the My Location layer.