Maps SDK для Android позволяет прослушивать события на карте.
Примеры кода
В репозитории ApiDemos на сайте GitHub вы найдете примеры, которые демонстрируют работу с событиями и прослушивателями:
Kotlin
- EventsDemoActivity: события кликов на карте и изменений положения камеры.
- CameraDemoActivity: события изменений положения камеры.
- CircleDemoActivity: события кликов и перетаскиваний маркера.
- GroundOverlayDemoActivity: события кликов по наземным наложениям.
- IndoorDemoActivity: события схем зданий.
- MarkerDemoActivity: события маркеров и информационных окон.
- PolygonDemoActivity: события многоугольников.
Java
- EventsDemoActivity: события кликов на карте и изменений положения камеры.
- CameraDemoActivity: события изменений положения камеры.
- CircleDemoActivity: события кликов и перетаскиваний маркера.
- GroundOverlayDemoActivity: события кликов по наземным наложениям.
- IndoorDemoActivity: события схем зданий.
- MarkerDemoActivity: события маркеров и информационных окон.
- PolygonDemoActivity: события многоугольников.
События кликов и долгих нажатий
Чтобы приложение реагировало на нажатие в определенной точке карты, используйте прослушиватель OnMapClickListener
, который устанавливается с помощью метода GoogleMap.setOnMapClickListener(OnMapClickListener)
. Когда пользователь нажимает точку на карте, инициируется событие onMapClick(LatLng)
, сообщающее координаты этой точки. Если вам требуются координаты соответствующей точки на экране в пикселях, вы можете запросить объект Projection
. Он позволяет переводить широту и долготу в экранные координаты в пикселях и обратно.
Кроме того, вы можете отслеживать долгие нажатия с помощью прослушивателя OnMapLongClickListener
. Чтобы добавить его на карту, вызовите GoogleMap.setOnMapLongClickListener(OnMapLongClickListener)
.
Он работает так же, как прослушиватель кликов. При обнаружении долгого нажатия инициируется метод обратного вызова onMapLongClick(LatLng)
.
Отключение событий кликов в упрощенном режиме
Чтобы отключить события кликов на карте в упрощенном режиме, вызовите метод setClickable()
в представлении, которое содержит MapView
или MapFragment
. Например, это удобно, когда карты представлены в виде списка и вам нужно, чтобы клик вызывал действие, не имеющее отношения к карте.
Отключать события кликов можно только в упрощенном режиме. Отключение этих событий также отключает реакцию маркеров на клики. Это не влияет на другие элементы управления картой.
Для MapView
:
val mapView = findViewById<MapView>(R.id.mapView)
mapView.isClickable = false
MapView mapView = findViewById(R.id.mapView);
mapView.setClickable(false);
Для MapFragment
:
val mapFragment = supportFragmentManager
.findFragmentById(R.id.map) as SupportMapFragment
val view = mapFragment.view
view?.isClickable = false
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
View view = mapFragment.getView();
view.setClickable(false);
События изменений положения и настроек камеры
Модель представления карты предполагает направление камеры вниз на плоскость. Для камеры можно задать уровень масштабирования, область просмотра и перспективу карты. Дополнительные сведения вы найдете в руководстве по работе с камерой. Пользователи также могут управлять камерой с помощью жестов.
Прослушиватели позволяют получать сведения о перемещении камеры: событиях начала, продолжения и окончания движения. Вы сможете также увидеть, почему камера движется: вызвано ли это жестами пользователя, встроенной анимацией API или движениями, которые контролируются разработчиками.
Следующий пример демонстрирует все доступные прослушиватели событий камеры:
/*
* 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 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.
*/
class CameraDemoActivity :
AppCompatActivity(),
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)
}
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)
}
}
// 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 AppCompatActivity 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(R.layout.camera_demo);
animateToggle = findViewById(R.id.animate);
customDurationToggle = findViewById(R.id.duration_toggle);
customDurationBar = findViewById(R.id.duration_bar);
updateEnabledState();
SupportMapFragment mapFragment =
(SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
}
@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, 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);
}
}
Доступны следующие прослушиватели камеры:
Когда камера начинает движение, выполняется обратный вызов метода
onCameraMoveStarted()
для прослушивателяOnCameraMoveStartedListener
. Методу обратного вызова передается параметрreason
, указывающий причину движения камеры. Причина может быть одной из следующих:REASON_GESTURE
указывает, что камера начала движение в ответ на жест пользователя на карте, такой как панорамирование, наклон, вращение карты, сведение или разведение пальцев для масштабирования.REASON_API_ANIMATION
указывает, что API вызвал движение камеры в ответ на действие пользователя, не связанное с жестами, такое как нажатие кнопки масштабирования, кнопки "Мое местоположение" или касание маркера.REASON_DEVELOPER_ANIMATION
указывает, что движение камеры инициировано приложением.
Во время движения камеры или при действиях пользователя на сенсорном экране несколько раз выполняется обратный вызов метода
onCameraMove()
для прослушивателяOnCameraMoveListener
. Полезно знать, что API выполняет обратный вызов один раз для каждого фрейма. Однако это делается асинхронно и, следовательно, не согласовано с тем, что видно на экране. Кроме того, следует учитывать, что камера может не изменять свое положение между двумя обратными вызовами методаonCameraMove()
.Когда камера прекращает движение, а пользователь не выполняет никаких действий с картой, происходит обратный вызов метода
OnCameraIdle()
для прослушивателяOnCameraIdleListener
.Обратный вызов метода
OnCameraMoveCanceled()
для прослушивателяOnCameraMoveCanceledListener
происходит, когда текущее движение камеры было прервано. Сразу же после обратного вызова методаOnCameraMoveCanceled()
выполняется обратный вызов методаonCameraMoveStarted()
с новым параметромreason
.Если ваше приложение явным образом вызывает метод
GoogleMap.stopAnimation()
, выполняется обратный вызов методаOnCameraMoveCanceled()
, но при этом обратный вызовonCameraMoveStarted()
не происходит.
Чтобы добавить прослушиватель на карту, необходимо вызвать соответствующий метод.
Например, для запроса обратного вызова из прослушивателя OnCameraMoveStartedListener
вызовите метод GoogleMap.setOnCameraMoveStartedListener()
.
Получить целевой объект камеры (широту и долготу), масштаб, направление и наклон можно из объекта CameraPosition
. Дополнительную информацию вы найдете в разделе о положении камеры.
События, связанные с организациями и другими объектами
По умолчанию объекты инфраструктуры отображаются на базовой карте вместе с соответствующими значками. К таким объектам относятся парки, школы, правительственные здания и прочее, а также коммерческие организации, например магазины, рестораны и гостиницы.
Вы можете обрабатывать события кликов для объектов. Подробнее о том, как это делать, рассказывается в руководстве по взаимодействию с организациями и объекты инфраструктуры.
События схем зданий
События можно использовать для поиска и настройки активного уровня схемы здания. Используйте интерфейс OnIndoorStateChangeListener
, чтобы настроить вызов прослушивателя, когда в фокус попадает новое здание или активируется новый уровень в нем.
Чтобы получить данные о здании, которое в настоящий момент находится в фокусе, вызовите GoogleMap.getFocusedBuilding()
.
Центрирование карты на определенной широте или долготе обычно позволяет получить информацию о здании по данным координатам, однако это не гарантируется.
После этого вы можете найти текущий активный уровень, вызвав метод IndoorBuilding.getActiveLevelIndex()
.
map.focusedBuilding?.let { building: IndoorBuilding ->
val activeLevelIndex = building.activeLevelIndex
val activeLevel = building.levels[activeLevelIndex]
}
IndoorBuilding building = map.getFocusedBuilding();
if (building != null) {
int activeLevelIndex = building.getActiveLevelIndex();
IndoorLevel activeLevel = building.getLevels().get(activeLevelIndex);
}
Это полезно, если вы хотите показывать на активном уровне пользовательскую разметку, например маркеры, наземные наложения, наложения фрагментов, многоугольники, ломаные линии и другие фигуры.
Совет. Чтобы вернуться на уровень улицы, запросите уровень по умолчанию с помощью метода IndoorBuilding.getDefaultLevelIndex()
и сделайте этот уровень активным с помощью метода IndoorLevel.activate()
.
События маркеров и информационных окон
Вы можете отслеживать события маркера, включая клики и перетаскивания, и реагировать на них, установив необходимый прослушиватель для объекта GoogleMap
, которому принадлежит этот маркер. Ознакомьтесь с руководством по событиям маркеров.
Вы также можете отслеживать события информационных окон.
События форм и наложений
Вы можете прослушивать и обрабатывать события кликов для ломаных линий, многоугольников, кругов и наземных наложений.
События местоположения
Ваше приложение может реагировать на перечисленные ниже события, связанные со слоем "Мое местоположение":
- Если пользователь нажимает кнопку "Мое местоположение", ваше приложение получает обратный вызов
onMyLocationButtonClick()
от прослушивателяGoogleMap.OnMyLocationButtonClickListener
. - Если пользователь нажимает на синюю точку "Мое местоположение", ваше приложение получает обратный вызов
onMyLocationClick()
от прослушивателяGoogleMap.OnMyLocationClickListener
.
Подробную информацию вы найдете в руководстве по работе со слоем "Мое местоположение".