Events

Select platform: Android iOS JavaScript

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

Java

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

 val 
  
 mapView 
  
 = 
  
 findViewById<MapView> 
 ( 
 R 
 . 
 id 
 . 
 mapView 
 ) 
 mapView 
 . 
 isClickable 
  
 = 
  
 false 
  

Java

 MapView 
  
 mapView 
  
 = 
  
 findViewById 
 ( 
 R 
 . 
 id 
 . 
 mapView 
 ); 
 mapView 
 . 
 setClickable 
 ( 
 false 
 ); 
  

For a MapFragment :

Kotlin

 val 
  
 mapFragment 
  
 = 
  
 supportFragmentManager 
  
 . 
 findFragmentById 
 ( 
 R 
 . 
 id 
 . 
 map 
 ) 
  
 as 
  
 SupportMapFragment 
 val 
  
 view 
  
 = 
  
 mapFragment 
 . 
 view 
 view 
 ?. 
 isClickable 
  
 = 
  
 false 
  

Java

 SupportMapFragment 
  
 mapFragment 
  
 = 
  
 ( 
 SupportMapFragment 
 ) 
  
 getSupportFragmentManager 
 () 
  
 . 
 findFragmentById 
 ( 
 R 
 . 
 id 
 . 
 map 
 ); 
 View 
  
 view 
  
 = 
  
 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. 
 */ 
 package 
  
 com.example.kotlindemos 
 import 
  
 android.graphics.Color 
 import 
  
 android.os.Bundle 
 import 
  
 android.util.Log 
 import 
  
 android.view.View 
 import 
  
 android.widget.CompoundButton 
 import 
  
 android.widget.SeekBar 
 import 
  
 android.widget.Toast 
 import 
  
 com.example.common_ui.R 
 import 
  
 com.google.android.gms.maps.CameraUpdate 
 import 
  
 com.google.android.gms.maps.CameraUpdateFactory 
 import 
  
 com.google.android.gms.maps.GoogleMap 
 import 
  
 com.google.android.gms.maps.GoogleMap.CancelableCallback 
 import 
  
 com.google.android.gms.maps.GoogleMap.OnCameraIdleListener 
 import 
  
 com.google.android.gms.maps.GoogleMap.OnCameraMoveCanceledListener 
 import 
  
 com.google.android.gms.maps.GoogleMap.OnCameraMoveListener 
 import 
  
 com.google.android.gms.maps.GoogleMap.OnCameraMoveStartedListener 
 import 
  
 com.google.android.gms.maps.OnMapReadyCallback 
 import 
  
 com.google.android.gms.maps.SupportMapFragment 
 import 
  
 com.google.android.gms.maps.model.CameraPosition 
 import 
  
 com.google.android.gms.maps.model.LatLng 
 import 
  
 com.google.android.gms.maps.model.PolylineOptions 
 /** 
 * This shows how to change the camera position for the map. 
 */ 
 class 
  
 CameraDemoActivity 
  
 : 
  
 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). 
 */ 
  
 private 
  
 val 
  
 SCROLL_BY_PX 
  
 = 
  
 100 
  
 private 
  
 val 
  
 TAG 
  
 = 
  
 CameraDemoActivity 
 :: 
 class 
 . 
 java 
 . 
 name 
  
 private 
  
 val 
  
 sydneyLatLng 
  
 = 
  
 LatLng 
 ( 
 - 
 33.87365 
 , 
  
 151.20689 
 ) 
  
 private 
  
 val 
  
 bondiLocation 
 : 
  
 CameraPosition 
  
 = 
  
 CameraPosition 
 . 
 Builder 
 () 
  
 . 
 target 
 ( 
 LatLng 
 ( 
 - 
 33.891614 
 , 
  
 151.276417 
 )) 
  
 . 
 zoom 
 ( 
 15.5f 
 ) 
  
 . 
 bearing 
 ( 
 300f 
 ) 
  
 . 
 tilt 
 ( 
 50f 
 ) 
  
 . 
 build 
 () 
  
 private 
  
 val 
  
 sydneyLocation 
 : 
  
 CameraPosition 
  
 = 
  
 CameraPosition 
 . 
 Builder 
 (). 
  
 target 
 ( 
 LatLng 
 ( 
 - 
 33.87365 
 , 
  
 151.20689 
 )) 
  
 . 
 zoom 
 ( 
 15.5f 
 ) 
  
 . 
 bearing 
 ( 
 0f 
 ) 
  
 . 
 tilt 
 ( 
 25f 
 ) 
  
 . 
 build 
 () 
  
 private 
  
 lateinit 
  
 var 
  
 map 
 : 
  
 GoogleMap 
  
 private 
  
 lateinit 
  
 var 
  
 animateToggle 
 : 
  
 CompoundButton 
  
 private 
  
 lateinit 
  
 var 
  
 customDurationToggle 
 : 
  
 CompoundButton 
  
 private 
  
 lateinit 
  
 var 
  
 customDurationBar 
 : 
  
 SeekBar 
  
 private 
  
 var 
  
 currPolylineOptions 
 : 
  
 PolylineOptions? 
 = 
  
 null 
  
 private 
  
 var 
  
 isCanceled 
  
 = 
  
 false 
  
 override 
  
 fun 
  
 onCreate 
 ( 
 savedInstanceState 
 : 
  
 Bundle?) 
  
 { 
  
 super 
 . 
 onCreate 
 ( 
 savedInstanceState 
 ) 
  
 setContentView 
 ( 
 R 
 . 
 layout 
 . 
 camera_demo 
 ) 
  
 animateToggle 
  
 = 
  
 findViewById 
 ( 
 R 
 . 
 id 
 . 
 animate 
 ) 
  
 customDurationToggle 
  
 = 
  
 findViewById 
 ( 
 R 
 . 
 id 
 . 
 duration_toggle 
 ) 
  
 customDurationBar 
  
 = 
  
 findViewById 
 ( 
 R 
 . 
 id 
 . 
 duration_bar 
 ) 
  
 updateEnabledState 
 () 
  
 val 
  
 mapFragment 
  
 = 
  
 supportFragmentManager 
 . 
 findFragmentById 
 ( 
 R 
 . 
 id 
 . 
 map 
 ) 
  
 as 
  
 SupportMapFragment 
  
 mapFragment 
 . 
 getMapAsync 
 ( 
 this 
 ) 
  
 applyInsets 
 ( 
 findViewById<View?>(R 
 . 
 id 
 . 
 map_container 
 )) 
  
 } 
  
 override 
  
 fun 
  
 onResume 
 () 
  
 { 
  
 super 
 . 
 onResume 
 () 
  
 updateEnabledState 
 () 
  
 } 
  
 override 
  
 fun 
  
 onMapReady 
 ( 
 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 
 */ 
  
 private 
  
 fun 
  
 checkReadyThen 
 ( 
 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" 
 ) 
  
 fun 
  
 onGoToBondi 
 ( 
 view 
 : 
  
 View 
 ) 
  
 { 
  
 checkReadyThen 
  
 { 
  
 changeCamera 
 ( 
 CameraUpdateFactory 
 . 
 newCameraPosition 
 ( 
 bondiLocation 
 )) 
  
 } 
  
 } 
  
 /** 
 * Called when the Animate To Sydney button is clicked. 
 */ 
  
 @Suppress 
 ( 
 "UNUSED_PARAMETER" 
 ) 
  
 fun 
  
 onGoToSydney 
 ( 
 view 
 : 
  
 View 
 ) 
  
 { 
  
 checkReadyThen 
  
 { 
  
 changeCamera 
 ( 
 CameraUpdateFactory 
 . 
 newCameraPosition 
 ( 
 sydneyLocation 
 ), 
  
 object 
  
 : 
  
 CancelableCallback 
  
 { 
  
 override 
  
 fun 
  
 onFinish 
 () 
  
 { 
  
 Toast 
 . 
 makeText 
 ( 
 baseContext 
 , 
  
 "Animation to Sydney complete" 
 , 
  
 Toast 
 . 
 LENGTH_SHORT 
 ). 
 show 
 () 
  
 } 
  
 override 
  
 fun 
  
 onCancel 
 () 
  
 { 
  
 Toast 
 . 
 makeText 
 ( 
 baseContext 
 , 
  
 "Animation to Sydney canceled" 
 , 
  
 Toast 
 . 
 LENGTH_SHORT 
 ). 
 show 
 () 
  
 } 
  
 }) 
  
 } 
  
 } 
  
 /** 
 * Called when the stop button is clicked. 
 */ 
  
 @Suppress 
 ( 
 "UNUSED_PARAMETER" 
 ) 
  
 fun 
  
 onStopAnimation 
 ( 
 view 
 : 
  
 View 
 ) 
  
 = 
  
 checkReadyThen 
  
 { 
  
 map 
 . 
 stopAnimation 
 () 
  
 } 
  
 /** 
 * Called when the zoom in button (the one with the +) is clicked. 
 */ 
  
 @Suppress 
 ( 
 "UNUSED_PARAMETER" 
 ) 
  
 fun 
  
 onZoomIn 
 ( 
 view 
 : 
  
 View 
 ) 
  
 = 
  
 checkReadyThen 
  
 { 
  
 changeCamera 
 ( 
 CameraUpdateFactory 
 . 
 zoomIn 
 ()) 
  
 } 
  
 /** 
 * Called when the zoom out button (the one with the -) is clicked. 
 */ 
  
 @Suppress 
 ( 
 "UNUSED_PARAMETER" 
 ) 
  
 fun 
  
 onZoomOut 
 ( 
 view 
 : 
  
 View 
 ) 
  
 = 
  
 checkReadyThen 
  
 { 
  
 changeCamera 
 ( 
 CameraUpdateFactory 
 . 
 zoomOut 
 ()) 
  
 } 
  
 /** 
 * Called when the tilt more button (the one with the /) is clicked. 
 */ 
  
 @Suppress 
 ( 
 "UNUSED_PARAMETER" 
 ) 
  
 fun 
  
 onTiltMore 
 ( 
 view 
 : 
  
 View 
 ) 
  
 { 
  
 checkReadyThen 
  
 { 
  
 val 
  
 newTilt 
  
 = 
  
 Math 
 . 
 min 
 ( 
 map 
 . 
 cameraPosition 
 . 
 tilt 
  
 + 
  
 10 
 , 
  
 90F 
 ) 
  
 val 
  
 cameraPosition 
  
 = 
  
 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" 
 ) 
  
 fun 
  
 onTiltLess 
 ( 
 view 
 : 
  
 View 
 ) 
  
 { 
  
 checkReadyThen 
  
 { 
  
 val 
  
 newTilt 
  
 = 
  
 Math 
 . 
 max 
 ( 
 map 
 . 
 cameraPosition 
 . 
 tilt 
  
 - 
  
 10 
 , 
  
 0F 
 ) 
  
 val 
  
 cameraPosition 
  
 = 
  
 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" 
 ) 
  
 fun 
  
 onScrollLeft 
 ( 
 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" 
 ) 
  
 fun 
  
 onScrollRight 
 ( 
 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" 
 ) 
  
 fun 
  
 onScrollUp 
 ( 
 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" 
 ) 
  
 fun 
  
 onScrollDown 
 ( 
 view 
 : 
  
 View 
 ) 
  
 { 
  
 checkReadyThen 
  
 { 
  
 changeCamera 
 ( 
 CameraUpdateFactory 
 . 
 scrollBy 
 ( 
 0f 
 , 
  
 SCROLL_BY_PX 
 . 
 toFloat 
 ())) 
  
 } 
  
 } 
  
 /** 
 * Called when the animate button is toggled 
 */ 
  
 @Suppress 
 ( 
 "UNUSED_PARAMETER" 
 ) 
  
 fun 
  
 onToggleAnimate 
 ( 
 view 
 : 
  
 View 
 ) 
  
 = 
  
 updateEnabledState 
 () 
  
 /** 
 * Called when the custom duration checkbox is toggled 
 */ 
  
 @Suppress 
 ( 
 "UNUSED_PARAMETER" 
 ) 
  
 fun 
  
 onToggleCustomDuration 
 ( 
 view 
 : 
  
 View 
 ) 
  
 = 
  
 updateEnabledState 
 () 
  
 /** 
 * Update the enabled state of the custom duration controls. 
 */ 
  
 private 
  
 fun 
  
 updateEnabledState 
 () 
  
 { 
  
 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. 
 */ 
  
 private 
  
 fun 
  
 changeCamera 
 ( 
 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 
 ) 
  
 } 
  
 } 
  
 override 
  
 fun 
  
 onCameraMoveStarted 
 ( 
 reason 
 : 
  
 Int 
 ) 
  
 { 
  
 if 
  
 ( 
 ! 
 isCanceled 
 ) 
  
 map 
 . 
 clear 
 () 
  
 var 
  
 reasonText 
  
 = 
  
 "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 
 */ 
  
 private 
  
 fun 
  
 checkPolylineThen 
 ( 
 stuffToDo 
 : 
  
 () 
  
 - 
>  
 Unit 
 ) 
  
 { 
  
 if 
  
 ( 
 currPolylineOptions 
  
 != 
  
 null 
 ) 
  
 stuffToDo 
 () 
  
 } 
  
 override 
  
 fun 
  
 onCameraMove 
 () 
  
 { 
  
 Log 
 . 
 d 
 ( 
 TAG 
 , 
  
 "onCameraMove" 
 ) 
  
 // When the camera is moving, add its target to the current path we'll draw on the map. 
  
 checkPolylineThen 
  
 { 
  
 addCameraTargetToPath 
 () 
  
 } 
  
 } 
  
 override 
  
 fun 
  
 onCameraMoveCanceled 
 () 
  
 { 
  
 // 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" 
 ) 
  
 } 
  
 override 
  
 fun 
  
 onCameraIdle 
 () 
  
 { 
  
 checkPolylineThen 
  
 { 
  
 addCameraTargetToPath 
 () 
  
 map 
 . 
 addPolyline 
 ( 
 currPolylineOptions 
 !! 
 ) 
  
 } 
  
 currPolylineOptions 
  
 = 
  
 null 
  
 isCanceled 
  
 = 
  
 false 
  
 // Set to *not* clear the map when dragging starts again. 
  
 Log 
 . 
 d 
 ( 
 TAG 
 , 
  
 "onCameraIdle" 
 ) 
  
 } 
  
 private 
  
 fun 
  
 addCameraTargetToPath 
 () 
  
 { 
  
 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. 
 package 
  
 com.example.mapdemo 
 ; 
 import 
  
 android.graphics.Color 
 ; 
 import 
  
 android.os.Bundle 
 ; 
 import 
  
 android.util.Log 
 ; 
 import 
  
 android.view.View 
 ; 
 import 
  
 android.widget.CompoundButton 
 ; 
 import 
  
 android.widget.SeekBar 
 ; 
 import 
  
 android.widget.Toast 
 ; 
 import 
  
 androidx.appcompat.app.AppCompatActivity 
 ; 
 import 
  
 com.google.android.gms.maps.CameraUpdate 
 ; 
 import 
  
 com.google.android.gms.maps.CameraUpdateFactory 
 ; 
 import 
  
 com.google.android.gms.maps.GoogleMap 
 ; 
 import 
  
 com.google.android.gms.maps.GoogleMap.CancelableCallback 
 ; 
 import 
  
 com.google.android.gms.maps.GoogleMap.OnCameraIdleListener 
 ; 
 import 
  
 com.google.android.gms.maps.GoogleMap.OnCameraMoveCanceledListener 
 ; 
 import 
  
 com.google.android.gms.maps.GoogleMap.OnCameraMoveListener 
 ; 
 import 
  
 com.google.android.gms.maps.GoogleMap.OnCameraMoveStartedListener 
 ; 
 import 
  
 com.google.android.gms.maps.OnMapReadyCallback 
 ; 
 import 
  
 com.google.android.gms.maps.SupportMapFragment 
 ; 
 import 
  
 com.google.android.gms.maps.model.CameraPosition 
 ; 
 import 
  
 com.google.android.gms.maps.model.LatLng 
 ; 
 import 
  
 com.google.android.gms.maps.model.PolylineOptions 
 ; 
 /** 
 * This shows how to change the camera position for the map. 
 */ 
 public 
  
 class 
 CameraDemoActivity 
  
 extends 
  
 SamplesBaseActivity 
  
 implements 
  
 OnCameraMoveStartedListener 
 , 
  
 OnCameraMoveListener 
 , 
  
 OnCameraMoveCanceledListener 
 , 
  
 OnCameraIdleListener 
 , 
  
 OnMapReadyCallback 
  
 { 
  
 private 
  
 static 
  
 final 
  
 String 
  
 TAG 
  
 = 
  
 CameraDemoActivity 
 . 
 class 
 . 
 getName 
 (); 
  
 /** 
 * The amount by which to scroll the camera. Note that this amount is in raw pixels, not dp 
 * (density-independent pixels). 
 */ 
  
 private 
  
 static 
  
 final 
  
 int 
  
 SCROLL_BY_PX 
  
 = 
  
 100 
 ; 
  
 public 
  
 static 
  
 final 
  
 CameraPosition 
  
 BONDI 
  
 = 
  
 new 
  
 CameraPosition 
 . 
 Builder 
 (). 
 target 
 ( 
 new 
  
 LatLng 
 ( 
 - 
 33.891614 
 , 
  
 151.276417 
 )) 
  
 . 
 zoom 
 ( 
 15.5f 
 ) 
  
 . 
 bearing 
 ( 
 300 
 ) 
  
 . 
 tilt 
 ( 
 50 
 ) 
  
 . 
 build 
 (); 
  
 public 
  
 static 
  
 final 
  
 CameraPosition 
  
 SYDNEY 
  
 = 
  
 new 
  
 CameraPosition 
 . 
 Builder 
 (). 
 target 
 ( 
 new 
  
 LatLng 
 ( 
 - 
 33.87365 
 , 
  
 151.20689 
 )) 
  
 . 
 zoom 
 ( 
 15.5f 
 ) 
  
 . 
 bearing 
 ( 
 0 
 ) 
  
 . 
 tilt 
 ( 
 25 
 ) 
  
 . 
 build 
 (); 
  
 private 
  
 GoogleMap 
  
 map 
 ; 
  
 private 
  
 CompoundButton 
  
 animateToggle 
 ; 
  
 private 
  
 CompoundButton 
  
 customDurationToggle 
 ; 
  
 private 
  
 SeekBar 
  
 customDurationBar 
 ; 
  
 private 
  
 PolylineOptions 
  
 currPolylineOptions 
 ; 
  
 private 
  
 boolean 
  
 isCanceled 
  
 = 
  
 false 
 ; 
  
 @Override 
  
 protected 
  
 void 
  
 onCreate 
 ( 
 Bundle 
  
 savedInstanceState 
 ) 
  
 { 
  
 super 
 . 
 onCreate 
 ( 
 savedInstanceState 
 ); 
  
 setContentView 
 ( 
 com 
 . 
 example 
 . 
 common_ui 
 . 
 R 
 . 
 layout 
 . 
 camera_demo 
 ); 
  
 animateToggle 
  
 = 
  
 findViewById 
 ( 
 com 
 . 
 example 
 . 
 common_ui 
 . 
 R 
 . 
 id 
 . 
 animate 
 ); 
  
 customDurationToggle 
  
 = 
  
 findViewById 
 ( 
 com 
 . 
 example 
 . 
 common_ui 
 . 
 R 
 . 
 id 
 . 
 duration_toggle 
 ); 
  
 customDurationBar 
  
 = 
  
 findViewById 
 ( 
 com 
 . 
 example 
 . 
 common_ui 
 . 
 R 
 . 
 id 
 . 
 duration_bar 
 ); 
  
 updateEnabledState 
 (); 
  
 SupportMapFragment 
  
 mapFragment 
  
 = 
  
 ( 
 SupportMapFragment 
 ) 
  
 getSupportFragmentManager 
 (). 
 findFragmentById 
 ( 
 com 
 . 
 example 
 . 
 common_ui 
 . 
 R 
 . 
 id 
 . 
 map 
 ); 
  
 mapFragment 
 . 
 getMapAsync 
 ( 
 this 
 ); 
  
 applyInsets 
 ( 
 findViewById 
 ( 
 com 
 . 
 example 
 . 
 common_ui 
 . 
 R 
 . 
 id 
 . 
 map_container 
 )); 
  
 } 
  
 @Override 
  
 protected 
  
 void 
  
 onResume 
 () 
  
 { 
  
 super 
 . 
 onResume 
 (); 
  
 updateEnabledState 
 (); 
  
 } 
  
 @Override 
  
 public 
  
 void 
  
 onMapReady 
 ( 
 GoogleMap 
  
 googleMap 
 ) 
  
 { 
  
 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 
 ( 
 new 
  
 LatLng 
 ( 
 - 
 33.87365 
 , 
  
 151.20689 
 ), 
  
 10 
 )); 
  
 } 
  
 /** 
 * 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. 
 */ 
  
 private 
  
 boolean 
  
 checkReady 
 () 
  
 { 
  
 if 
  
 ( 
 map 
  
 == 
  
 null 
 ) 
  
 { 
  
 Toast 
 . 
 makeText 
 ( 
 this 
 , 
  
 com 
 . 
 example 
 . 
 common_ui 
 . 
 R 
 . 
 string 
 . 
 map_not_ready 
 , 
  
 Toast 
 . 
 LENGTH_SHORT 
 ). 
 show 
 (); 
  
 return 
  
 false 
 ; 
  
 } 
  
 return 
  
 true 
 ; 
  
 } 
  
 /** 
 * Called when the Go To Bondi button is clicked. 
 */ 
  
 public 
  
 void 
  
 onGoToBondi 
 ( 
 View 
  
 view 
 ) 
  
 { 
  
 if 
  
 ( 
 ! 
 checkReady 
 ()) 
  
 { 
  
 return 
 ; 
  
 } 
  
 changeCamera 
 ( 
 CameraUpdateFactory 
 . 
 newCameraPosition 
 ( 
 BONDI 
 )); 
  
 } 
  
 /** 
 * Called when the Animate To Sydney button is clicked. 
 */ 
  
 public 
  
 void 
  
 onGoToSydney 
 ( 
 View 
  
 view 
 ) 
  
 { 
  
 if 
  
 ( 
 ! 
 checkReady 
 ()) 
  
 { 
  
 return 
 ; 
  
 } 
  
 changeCamera 
 ( 
 CameraUpdateFactory 
 . 
 newCameraPosition 
 ( 
 SYDNEY 
 ), 
  
 new 
  
 CancelableCallback 
 () 
  
 { 
  
 @Override 
  
 public 
  
 void 
  
 onFinish 
 () 
  
 { 
  
 Toast 
 . 
 makeText 
 ( 
 getBaseContext 
 (), 
  
 "Animation to Sydney complete" 
 , 
  
 Toast 
 . 
 LENGTH_SHORT 
 ) 
  
 . 
 show 
 (); 
  
 } 
  
 @Override 
  
 public 
  
 void 
  
 onCancel 
 () 
  
 { 
  
 Toast 
 . 
 makeText 
 ( 
 getBaseContext 
 (), 
  
 "Animation to Sydney canceled" 
 , 
  
 Toast 
 . 
 LENGTH_SHORT 
 ) 
  
 . 
 show 
 (); 
  
 } 
  
 }); 
  
 } 
  
 /** 
 * Called when the stop button is clicked. 
 */ 
  
 public 
  
 void 
  
 onStopAnimation 
 ( 
 View 
  
 view 
 ) 
  
 { 
  
 if 
  
 ( 
 ! 
 checkReady 
 ()) 
  
 { 
  
 return 
 ; 
  
 } 
  
 map 
 . 
 stopAnimation 
 (); 
  
 } 
  
 /** 
 * Called when the zoom in button (the one with the +) is clicked. 
 */ 
  
 public 
  
 void 
  
 onZoomIn 
 ( 
 View 
  
 view 
 ) 
  
 { 
  
 if 
  
 ( 
 ! 
 checkReady 
 ()) 
  
 { 
  
 return 
 ; 
  
 } 
  
 changeCamera 
 ( 
 CameraUpdateFactory 
 . 
 zoomIn 
 ()); 
  
 } 
  
 /** 
 * Called when the zoom out button (the one with the -) is clicked. 
 */ 
  
 public 
  
 void 
  
 onZoomOut 
 ( 
 View 
  
 view 
 ) 
  
 { 
  
 if 
  
 ( 
 ! 
 checkReady 
 ()) 
  
 { 
  
 return 
 ; 
  
 } 
  
 changeCamera 
 ( 
 CameraUpdateFactory 
 . 
 zoomOut 
 ()); 
  
 } 
  
 /** 
 * Called when the tilt more button (the one with the /) is clicked. 
 */ 
  
 public 
  
 void 
  
 onTiltMore 
 ( 
 View 
  
 view 
 ) 
  
 { 
  
 if 
  
 ( 
 ! 
 checkReady 
 ()) 
  
 { 
  
 return 
 ; 
  
 } 
  
 CameraPosition 
  
 currentCameraPosition 
  
 = 
  
 map 
 . 
 getCameraPosition 
 (); 
  
 float 
  
 currentTilt 
  
 = 
  
 currentCameraPosition 
 . 
 tilt 
 ; 
  
 float 
  
 newTilt 
  
 = 
  
 currentTilt 
  
 + 
  
 10 
 ; 
  
 newTilt 
  
 = 
  
 ( 
 newTilt 
 > 
 90 
 ) 
  
 ? 
  
 90 
  
 : 
  
 newTilt 
 ; 
  
 CameraPosition 
  
 cameraPosition 
  
 = 
  
 new 
  
 CameraPosition 
 . 
 Builder 
 ( 
 currentCameraPosition 
 ) 
  
 . 
 tilt 
 ( 
 newTilt 
 ). 
 build 
 (); 
  
 changeCamera 
 ( 
 CameraUpdateFactory 
 . 
 newCameraPosition 
 ( 
 cameraPosition 
 )); 
  
 } 
  
 /** 
 * Called when the tilt less button (the one with the \) is clicked. 
 */ 
  
 public 
  
 void 
  
 onTiltLess 
 ( 
 View 
  
 view 
 ) 
  
 { 
  
 if 
  
 ( 
 ! 
 checkReady 
 ()) 
  
 { 
  
 return 
 ; 
  
 } 
  
 CameraPosition 
  
 currentCameraPosition 
  
 = 
  
 map 
 . 
 getCameraPosition 
 (); 
  
 float 
  
 currentTilt 
  
 = 
  
 currentCameraPosition 
 . 
 tilt 
 ; 
  
 float 
  
 newTilt 
  
 = 
  
 currentTilt 
  
 - 
  
 10 
 ; 
  
 newTilt 
  
 = 
  
 ( 
 newTilt 
 > 
 0 
 ) 
  
 ? 
  
 newTilt 
  
 : 
  
 0 
 ; 
  
 CameraPosition 
  
 cameraPosition 
  
 = 
  
 new 
  
 CameraPosition 
 . 
 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 
 */ 
  
 public 
  
 void 
  
 onScrollLeft 
 ( 
 View 
  
 view 
 ) 
  
 { 
  
 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. 
 */ 
  
 public 
  
 void 
  
 onScrollRight 
 ( 
 View 
  
 view 
 ) 
  
 { 
  
 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. 
 */ 
  
 public 
  
 void 
  
 onScrollUp 
 ( 
 View 
  
 view 
 ) 
  
 { 
  
 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. 
 */ 
  
 public 
  
 void 
  
 onScrollDown 
 ( 
 View 
  
 view 
 ) 
  
 { 
  
 if 
  
 ( 
 ! 
 checkReady 
 ()) 
  
 { 
  
 return 
 ; 
  
 } 
  
 changeCamera 
 ( 
 CameraUpdateFactory 
 . 
 scrollBy 
 ( 
 0 
 , 
  
 SCROLL_BY_PX 
 )); 
  
 } 
  
 /** 
 * Called when the animate button is toggled 
 */ 
  
 public 
  
 void 
  
 onToggleAnimate 
 ( 
 View 
  
 view 
 ) 
  
 { 
  
 updateEnabledState 
 (); 
  
 } 
  
 /** 
 * Called when the custom duration checkbox is toggled 
 */ 
  
 public 
  
 void 
  
 onToggleCustomDuration 
 ( 
 View 
  
 view 
 ) 
  
 { 
  
 updateEnabledState 
 (); 
  
 } 
  
 /** 
 * Update the enabled state of the custom duration controls. 
 */ 
  
 private 
  
 void 
  
 updateEnabledState 
 () 
  
 { 
  
 customDurationToggle 
 . 
 setEnabled 
 ( 
 animateToggle 
 . 
 isChecked 
 ()); 
  
 customDurationBar 
  
 . 
 setEnabled 
 ( 
 animateToggle 
 . 
 isChecked 
 () 
 && 
 customDurationToggle 
 . 
 isChecked 
 ()); 
  
 } 
  
 private 
  
 void 
  
 changeCamera 
 ( 
 CameraUpdate 
  
 update 
 ) 
  
 { 
  
 changeCamera 
 ( 
 update 
 , 
  
 null 
 ); 
  
 } 
  
 /** 
 * Change the camera position by moving or animating the camera depending on the state of the 
 * animate toggle button. 
 */ 
  
 private 
  
 void 
  
 changeCamera 
 ( 
 CameraUpdate 
  
 update 
 , 
  
 CancelableCallback 
  
 callback 
 ) 
  
 { 
  
 if 
  
 ( 
 animateToggle 
 . 
 isChecked 
 ()) 
  
 { 
  
 if 
  
 ( 
 customDurationToggle 
 . 
 isChecked 
 ()) 
  
 { 
  
 int 
  
 duration 
  
 = 
  
 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 
  
 public 
  
 void 
  
 onCameraMoveStarted 
 ( 
 int 
  
 reason 
 ) 
  
 { 
  
 if 
  
 ( 
 ! 
 isCanceled 
 ) 
  
 { 
  
 map 
 . 
 clear 
 (); 
  
 } 
  
 String 
  
 reasonText 
  
 = 
  
 "UNKNOWN_REASON" 
 ; 
  
 currPolylineOptions 
  
 = 
  
 new 
  
 PolylineOptions 
 (). 
 width 
 ( 
 5 
 ); 
  
 switch 
  
 ( 
 reason 
 ) 
  
 { 
  
 case 
  
 OnCameraMoveStartedListener 
 . 
 REASON_GESTURE 
 : 
  
 currPolylineOptions 
 . 
 color 
 ( 
 Color 
 . 
 BLUE 
 ); 
  
 reasonText 
  
 = 
  
 "GESTURE" 
 ; 
  
 break 
 ; 
  
 case 
  
 OnCameraMoveStartedListener 
 . 
 REASON_API_ANIMATION 
 : 
  
 currPolylineOptions 
 . 
 color 
 ( 
 Color 
 . 
 RED 
 ); 
  
 reasonText 
  
 = 
  
 "API_ANIMATION" 
 ; 
  
 break 
 ; 
  
 case 
  
 OnCameraMoveStartedListener 
 . 
 REASON_DEVELOPER_ANIMATION 
 : 
  
 currPolylineOptions 
 . 
 color 
 ( 
 Color 
 . 
 GREEN 
 ); 
  
 reasonText 
  
 = 
  
 "DEVELOPER_ANIMATION" 
 ; 
  
 break 
 ; 
  
 } 
  
 Log 
 . 
 d 
 ( 
 TAG 
 , 
  
 "onCameraMoveStarted(" 
  
 + 
  
 reasonText 
  
 + 
  
 ")" 
 ); 
  
 addCameraTargetToPath 
 (); 
  
 } 
  
 @Override 
  
 public 
  
 void 
  
 onCameraMove 
 () 
  
 { 
  
 // 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 
  
 public 
  
 void 
  
 onCameraMoveCanceled 
 () 
  
 { 
  
 // 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 
  
 public 
  
 void 
  
 onCameraIdle 
 () 
  
 { 
  
 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" 
 ); 
  
 } 
  
 private 
  
 void 
  
 addCameraTargetToPath 
 () 
  
 { 
  
 LatLng 
  
 target 
  
 = 
  
 map 
 . 
 getCameraPosition 
 (). 
 target 
 ; 
  
 currPolylineOptions 
 . 
 add 
 ( 
 target 
 ); 
  
 } 
 } 
  

The following camera listeners are available:

  • The onCameraMoveStarted() callback of the OnCameraMoveStartedListener is invoked when the camera starts moving. The callback method receives a reason for the camera motion. The reason can be one of the following:

    • REASON_GESTURE indicates 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_ANIMATION indicates 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_ANIMATION indicates that your app has initiated the camera movement.
  • The onCameraMove() callback of the OnCameraMoveListener is 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 one onCameraMove() callback and the next.

  • The OnCameraIdle() callback of the OnCameraIdleListener is invoked when the camera stops moving and the user has stopped interacting with the map.

  • The OnCameraMoveCanceled() callback of the OnCameraMoveCanceledListener is invoked when the current camera movement has been interrupted. Immediately after the OnCameraMoveCanceled() callback, the onCameraMoveStarted() callback is invoked with the new reason .

    If your app explicitly calls GoogleMap.stopAnimation() , the OnCameraMoveCanceled() callback is invoked, but the onCameraMoveStarted() callback is notinvoked.

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 
  
 - 
>  
 val 
  
 activeLevelIndex 
  
 = 
  
 building 
 . 
 activeLevelIndex 
  
 val 
  
 activeLevel 
  
 = 
  
 building 
 . 
 levels 
 [ 
 activeLevelIndex 
 ] 
 } 
  

Java

 IndoorBuilding 
  
 building 
  
 = 
  
 map 
 . 
 getFocusedBuilding 
 (); 
 if 
  
 ( 
 building 
  
 != 
  
 null 
 ) 
  
 { 
  
 int 
  
 activeLevelIndex 
  
 = 
  
 building 
 . 
 getActiveLevelIndex 
 (); 
  
 IndoorLevel 
  
 activeLevel 
  
 = 
  
 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:

For details, see the guide to the My Location layer .

Create a Mobile Website
View Site in Mobile | Classic
Share by: