Карта | Mobile SDK | 2GIS Documentation
Android SDK

Карта

Чтобы создать карту, добавьте MapView в ваш activity:

<ru.dgis.sdk.map.MapView
    android:id="@+id/mapView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:dgis_cameraTargetLat="55.740444"
    app:dgis_cameraTargetLng="37.619524"
    app:dgis_cameraZoom="16.0"
/>

Для карты можно указать начальные координаты (cameraTargetLat - широта; cameraTargetLng - долгота) и масштаб (cameraZoom).

MapView также можно создать программно. В таком случае настройки можно указать в виде объекта MapOptions.

Объект карты (Map) можно получить, вызвав метод getMapAsync():

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    val sdkContext = DGis.initialize(applicationContext, apiKeys)
    setContentView(R.layout.activity_main)

    val mapView = findViewById<MapView>(R.id.mapView)
    lifecycle.addObserver(mapView)

    mapView.getMapAsync { map ->
        // Действия с картой
        val camera = map.camera
    }
}

В некоторых случаях для добавления объектов на карту нужно создать специальный объект - источник данных. Источники данных выступают в роли менеджеров объектов: вместо добавления объектов на карту напрямую, на карту добавляется источник данных и вся последующая работа с объектами происходит через него.

Источники данных бывают разных типов: движущиеся маркеры, маршруты с отображением текущей загруженности дорог, произвольные геометрические фигуры и т.д. Для каждого типа данных существует свой класс.

В общем случае работа с источниками данных выглядит следующим образом:

// Создание источника данных
val source = MyMapObjectSource(
    sdkContext,
    ...
)

// Добавление источника данных на карту
map.addSource(source)

// Добавление и удаление объектов в источнике данных
source.addObject(...)
source.removeObject(...)

Чтобы удалить созданный источник данных и все связанные с ним объекты, нужно вызвать метод карты removeSource():

map.removeSource(source)

Список активных источников данных можно получить, используя свойство map.sources.

Для добавления динамических объектов на карту (маркеров, линий, кругов, многоугольников) нужно создать менеджер объектов (MapObjectManager), указав объект карты. При удалении менеджера объектов удаляются все связанные с ним объекты на карте, поэтому его нужно сохранить в activity.

mapObjectManager = MapObjectManager(map)

Для добавления объектов используются методы addObject() и addObjects(). Для каждого динамического объекта можно указать поле userData, которое будет хранить произвольные данные, связанные с объектом. Настройки объектов можно менять после их создания.

Для удаления объектов используются методы removeObject() и removeObjects(). Чтобы удалить все объекты, можно использовать метод removeAll().

Чтобы добавить маркер на карту, нужно создать объект Marker, указав нужные настройки, и передать его в вызов addObject() менеджера объектов.

В настройках нужно указать координаты маркера (параметр position).

val marker = Marker(
    MarkerOptions(
        position = GeoPointWithElevation(
            latitude = 55.752425,
            longitude = 37.613983
        )
    )
)

mapObjectManager.addObject(marker)

Чтобы изменить иконку маркера, нужно указать объект Image в качестве параметра icon. Создать Image можно с помощью следующих функций:

val icon = imageFromResource(sdkContext, R.drawable.ic_marker)

val marker = Marker(
    MarkerOptions(
        position = GeoPointWithElevation(
            latitude = 55.752425,
            longitude = 37.613983
        ),
        icon = icon
    )
)

Чтобы изменить точку привязки иконки (выравнивание иконки относительно координат на карте), нужно указать параметр anchor.

Дополнительно можно указать текст для маркера и другие настройки (см. MarkerOptions).

Чтобы нарисовать на карте линию, нужно создать объект Polyline, указав нужные настройки, и передать его в вызов addObject() менеджера объектов.

Кроме списка координат для точек линии, в настройках можно указать ширину линии, цвет, пунктир, обводку и другие параметры (см. PolylineOptions).

// Координаты вершин ломаной линии
val points = listOf(
    GeoPoint(latitude = 55.7513, longitude = 37.6236),
    GeoPoint(latitude = 55.7405, longitude = 37.6235),
    GeoPoint(latitude = 55.7439, longitude = 37.6506)
)

// Создание линии
val polyline = Polyline(
    PolylineOptions(
        points = points,
        width = 2.lpx
    )
)

// Добавление линии на карту
mapObjectManager.addObject(polyline)

Свойство-расширение .lpx преобразует целое число в объект LogicalPixel.

Чтобы нарисовать на карте многоугольник, нужно создать объект Polygon, указав нужные настройки, и передать его в вызов addObject() менеджера объектов.

Координаты для многоугольника указываются в виде двумерного списка. Первый вложенный список должен содержать координаты основных вершин многоугольника. Остальные вложенные списки не обязательны и могут быть заданы для того, чтобы создать вырез внутри многоугольника (один дополнительный список - один вырез в виде многоугольника).

Дополнительно можно указать цвет полигона и параметры обводки (см. PolygonOptions).

val polygon = Polygon(
    PolygonOptions(
        contours = listOf(
            // Вершины многоугольника
            listOf(
                GeoPoint(latitude = 55.72014932919687, longitude = 37.562599182128906),
                GeoPoint(latitude = 55.72014932919687, longitude = 37.67555236816406),
                GeoPoint(latitude = 55.78004852149085, longitude = 37.67555236816406),
                GeoPoint(latitude = 55.78004852149085, longitude = 37.562599182128906),
                GeoPoint(latitude = 55.72014932919687, longitude = 37.562599182128906)
            ),
            // Координаты для выреза внутри многоугольника
            listOf(
                GeoPoint(latitude = 55.754167897761, longitude = 37.62422561645508),
                GeoPoint(latitude = 55.74450654680055, longitude = 37.61238098144531),
                GeoPoint(latitude = 55.74460317215391, longitude = 37.63435363769531),
                GeoPoint(latitude = 55.754167897761, longitude = 37.62422561645508)
            )
        ),
        borderWidth = 1.lpx
    )
)

mapObjectManager.addObject(polygon)

Для добавления маркеров на карту в режиме кластеризации нужно создать менеджер объектов (MapObjectManager) через MapObjectManager.withClustering(), указав инстанс карты, расстояние между кластерами в логических пикселях, максимальный zoom-уровень формирования кластеров и пользовательскую имплементацию протокола SimpleClusterRenderer. SimpleClusterRenderer используется для кастомизации кластеров в MapObjectManager.

val clusterRenderer = object : SimpleClusterRenderer {
    override fun renderCluster(cluster: SimpleClusterObject): SimpleClusterOptions {
        val textStyle = TextStyle(
            fontSize = LogicalPixel(15.0f),
            textPlacement = TextPlacement.RIGHT_TOP
        )
        val objectCount = cluster.objectCount
        val iconMapDirection = if (objectCount < 5) MapDirection(45.0) else null
        return SimpleClusterOptions(
            icon,
            iconWidth = LogicalPixel(30.0f),
            text = objectCount.toString(),
            textStyle = textStyle,
            iconMapDirection = iconMapDirection,
            userData = objectCount.toString()
        )
    }
}

mapObjectManager = MapObjectManager.withClustering(map, LogicalPixel(80.0f), Zoom(18.0f), clusterRenderer)

Для работы с камерой используется объект Camera, доступный через свойство map.camera.

Чтобы запустить анимацию перелёта камеры, нужно вызвать метод move() и указать параметры перелёта:

  • position - конечная позиция камеры (координаты и уровень приближения). Дополнительно можно указать наклон и поворот камеры (см. CameraPosition).
  • time - продолжительность перелёта в секундах (Duration).
  • animationType - тип анимации (CameraAnimationType).

Функция move() возвращает объект Future, который можно использовать, чтобы обработать событие завершения перелёта.

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

mapView.getMapAsync { map ->
    val cameraPosition = CameraPosition(
        point = GeoPoint(latitude = 55.752425, longitude = 37.613983),
        zoom = Zoom(16.0),
        tilt = Tilt(25.0),
        bearing = Arcdegree(85.0)
    )

    map.camera.move(cameraPosition, Duration.ofSeconds(2), CameraAnimationType.LINEAR).onResult {
        Log.d("APP", "Перелёт камеры завершён.")
    }
}

Для указания продолжительности перелёта можно использовать расширение .seconds:

map.camera.move(cameraPosition, 2.seconds, CameraAnimationType.LINEAR)

Для более точного контроля над анимацией перелёта можно использовать контроллер перелёта, который будет определять позицию камеры в каждый конкретный момент времени. Для этого нужно реализовать интерфейс CameraMoveController и передать созданный объект в метод move() вместо параметров перелёта.

Текущее состояние камеры (находится ли камера в полёте) можно получить, используя свойство state. См. CameraState для списка возможных состояний камеры.

val currentState = map.camera.state

Подписаться на изменения состояния камеры можно с помощью свойства stateChannel.

// Подписка
val connection = map.camera.stateChannel.connect { state ->
    Log.d("APP", "Состояние камеры изменилось на ${state}")
}

// Отписка
connection.close()

Текущую позицию камеры можно получить, используя свойство position (см. объект CameraPosition).

val currentPosition = map.camera.position

Log.d("APP", "Координаты: ${currentPosition.point}")
Log.d("APP", "Приближение: ${currentPosition.zoom}")
Log.d("APP", "Наклон: ${currentPosition.tilt}")
Log.d("APP", "Поворот: ${currentPosition.bearing}")

Подписаться на изменения позиции камеры (и угла наклона/поворота) можно с помощью свойства positionChannel.

// Подписка
val connection = map.camera.positionChannel.connect { position ->
    Log.d("APP", "Изменилась позиция камеры или угол наклона/поворота.")
}

// Отписка
connection.close()

На карту можно добавить специальный маркер, который будет отражать текущее местоположение устройства. Для этого нужно добавить на карту источник данных MyLocationMapObjectSource.

// Создание источника данных
val source = MyLocationMapObjectSource(
    sdkContext,
    MyLocationDirectionBehaviour.FOLLOW_SATELLITE_HEADING,
    createSmoothMyLocationController()
)

// Добавление источника данных на карту
map.addSource(source)

Информацию об объектах на карте можно получить, используя пиксельные координаты. Для этого нужно вызвать метод карты getRenderedObjects(), указав координаты в пикселях и радиус в экранных миллиметрах. Метод вернет отложенный результат, содержащий информацию обо всех найденных объектах в указанном радиусе на видимой области карты (список RenderedObjectInfo).

Пример функции, которая принимает координаты нажатия на экран и передаёт их в метод getRenderedObjects():

override fun onTap(point: ScreenPoint) {
    map.getRenderedObjects(point, ScreenDistance(5f)).onResult { renderedObjectInfos ->
        // Первый объект в списке - самый близкий к координатам
        for (renderedObjectInfo in renderedObjectInfos) {
            Log.d("APP", "Произвольные данные объекта: ${renderedObjectInfo.item.item.userData}")
        }
    }
}