iOS
Подключение
Для подключения MapsSDK вы можете использовать Swift Package Manager.
Установка с помощью Swift Package Manager
MapsSDK доступен в виде пакета для Swift Package Manager (SPM). SPM — это менеджер зависимостей, он интегрирован в систему сборки Swift и автоматизирует процесс загрузки, компиляции и линковки зависимостей. Для установки пакета выполните следующие действия:
- Откройте проект в Xcode.
- Нажмите File -> Add Packages.
Также вы можете выбрать файл проекта на панели Project Navigator, перейти к настройкам проекта, далее выбрать вкладку Package Dependencies и нажать кнопку Add Package Dependency.
В появившемся окне введите адрес репозитория: https://github.com/geors/maps-sdk-ios.
Интеграция карт в приложение
Импортируйте MapsSDK в файл, в котором вы будете использовать карту.
import MapsSDK |
Для начала работы с картой необходимо:
- Создать объект типа MapView.
- Сконфигурировать карту.
- Указать делегат карты.
Создание объекта MapView
let mapView = MapView() |
Конфигурация объекта MapView
Для конфигурации необходимо создать объект типа MapViewConfig, содержащий следующие сведения:
- API-ключ для работы с SDK;
- координаты центра карты;
- начальный уровень zoom;
- стиль тайлов.
Пример настройки и установки конфигурации
let mapConfig = MapViewConfig ( apiKey : "##API_KEY##" , center : Coordinates ( lng : 33, lat : 55), zoomLevel : 11, style : . automatic ) mapView . setup ( mapConfig ) |
Уровень зума (zoomLevel) может иметь значение от 0 (самый отдаленный) до 22 (самый приближенный). Стиль тайлов (style) может принять одно из следующих значений:
- .automatic — автоматический выбор стиля в зависимости от isDriveMode и текущей цветовой схемы устройства;
- .main — базовый стиль;
- .light — светлый стиль;
- .dark — темный стиль;
- .navMain — базовый стиль для навигации с акцентом на дороги;
- .navDark — темный стиль для навигации с акцентом на дороги.
Указание делегата карты
Делегат должен реализовывать требования протокола MapViewDelegate. Он будет использоваться для обработки оповещений от карты о различных событиях, таких как:
- карта была загружена;
- было получено событие, иницированное пользователем (например касание);
- было получено событие, инициированное элементами управления картой и т.д.
Пример интеграции карты в приложение
import MapsSDK ... override func viewDidLoad () { let mapView = MapView () let mapConfig = MapViewConfig ( apiKey : "##API_KEY##" , center : Coordinates ( lng : 33, lat : 55), zoomLevel : 11, style : . automatic ) mapView . setup ( mapConfig ) mapView . delegate = self view . addSubview ( mapView ) } |
Использование и управление картой
Установка текущих параметров пользователя
Метод setCurrentLocation устанавливает:
- текущие координаты пользователя;
- направление, в котором смотрит или движется пользователь (bearing);
- точность позиции пользователя в метрах (accuracy);
- уровень зума (zoom). Данный аргумент является опциональным.
Установка текущей координаты и направления пользователя
// без установки зума mapView . setCurrentLocation ( Coordinates ( lng : 33, lat : 55), bearing : 0, accuracy : 0) // с установкой зума mapView . setCurrentLocation ( Coordinates ( lng : 33, lat : 55), bearing : 0, accuracy : 0, zoom : 10) |
Уровень зума (zoom) может изменяться в диапазоне от 0 (самый отдаленный) до 22 (самый приближенный).
Управление камерой
Метод flyTo
Позволяет изменить координаты центра карты. За анимацию изменений отвечает аргумент animated, а за длительность — duration.
// без указания длительности анимации mapView . flyTo ( Coordinates ( lng : 33, lat : 55), animated : true ) // с указание длительности анимации mapView . flyTo ( Coordinates ( lng : 33, lat : 55), animated : true , duration : 2) |
Дополнительно вы можете передать аргумент options типа MapCameraOptions, определяющий:
- азимут (bearing) — угол поворота карты;
- зум (zoom) — уровень зума карты;
- отступы (padding) — отступы с каждой стороны окна для смещения центральной точки вьюпорта;
- кривую движения камеры (curve) — коэфициент для определения траектории движения камеры;
- флаг сброса режима следования (resetFollowMode) - см. раздел «Установка режимов следования».
Каждый из перечисленных параметров является опциональным.
Пример метода flyTo с дополнительными опциями MapCameraOptions
let options = MapCameraOptions ( bearing : 180, zoom : 12, padding : UIEdgeInsets . init ( top : 20, left : 20, bottom : 150, right : 20), curve : 1.42, resetFollowMode : false ) mapView . flyTo ( Coordinates ( lng : 33, lat : 55), options : options , animated : true ) |
Установка направления карты
Метод setBearing устанавливает направление карты и является облегченной версией метода flyTo.
mapView.setBearing(90, animated: true) |
Фиксация севера карты сверху
Свойство isNorthAlwaysUp запрещает вращать карту любым способом, если установлено в true. Север будет всегда сверху карты. По умолчанию false.
mapView.isNorthAlwaysUp = true |
Скрытие маркера текущей локации
Cвойство isCurrentLocationHidden позволяет скрывать маркер текущей локации, когда она определена. По умолчанию false.
|
Установка уровня зума
Метод setZoom устанавливает зум карты и является облегченной версией метода flyTo.
mapView.setZoom(11, animated: true) |
Установка режимов следования (followLocation, followBearingAndLocation, free)
mapView.mode = .followLocation |
Вписывание области во вьюпорт
mapView.fitBounds(northWest: coords1, southEast: coords2, animated: true) |
Дополнительные возможности карты
Установка минимального и максимального уровня зума
mapView.setMinZoom(10, maxZoom: 15) |
Включение и выключение элементов управления
mapView . isZoomButtonsHidden = true mapView . isCompassHidden = true mapView . isMyLocationButtonHidden = true |
Включение и выключение жестов
mapView . isDragPanEnabled = true mapView . isZoomRotateEnabled = true |
Выравнивание логотипа
mapView . logoAlignment = . bottomRight mapView . logoIgnoresSafeArea = false mapView . logoInsets = . zero |
По умолчанию логотип отображается в нижнем правом углу карты и учитывает safeArea.
Маркеры
Для создания маркеров используется структура Marker. В инициализатор передаются уникальный идентификатор маркера, координату и картинку, а также, опционально, выравнивание. Для картинки рекомендуется использовать изображение размером 48х48 пикселей. Можно использовать набор из предоставляемых картинок или использовать свою собственную.
Добавление отдельных маркеров
let marker1 = Marker ( id : "marker_id_1" , coords : Coordinates ( lng : 33, lat : 55), pin : . electricPin ) let marker2 = Marker ( id : "marker_id_2" , coords : Coordinates ( lng : 33, lat : 55), pin : . electricInfo , alignment : . bottomLeft ) |
В данном случае передаются картинки из предустановленного в SDK набора изображений. При необходимости вы можете передать собственное изображение.
let markerImage = UIImage (...) let marker3 = Marker ( id : "marker_id_3" , coords : Coordinates ( lng : 33, lat : 55), pin : . custom ( markerImage ), alignment : . center ) |
По умолчанию выравнивание маркера имеет значение .center, то есть центр маркера совмещается с переданными координатами. У вас есть возможность гибко управлять этим параметром, выбирая одно из множества доступных значений, или передать произвольное смещение.
// Выравнивание по центру нижней грани let marker4 = Marker ( id : "marker_id_4" , coords : Coordinates ( lng : 33, lat : 55), pin : . electricPhoto , alignment : . bottom ) // Выравнивание со смещением // Смещение высчитывается относительно центра маркера let marker5 = Marker ( id : "marker_id_5" , coords : Coordinates ( lng : 33, lat : 55), pin : . electricStar , alignment : . center ( offsetByX : 10, byY : -10)) |
Для размещения маркера на карте используется метод addMarker(_: Marker).
Добавление маркеров по одному
mapView.addMarker(marker1) mapView.addMarker(marker2) |
Добавление маркеров массивом
mapView.addMarkers([marker1, marker2]) |
Удаление отдельного маркера с указанием его идентификатора
mapView.removeMarker(id: "marker_id_1") |
Удаление всех маркеров
mapView.removeAllMarkers() |
Отслеживание события нажатия на маркер
func MapDelegate : MapViewDelegate { func mapView ( _ map : MapView , didSelectMarkerID markerID : String ) { // ... // markerID - ID выбранного маркера // ... } } |
Дополнительно при нажатии на любой маркер вызывается метод MapViewDelegate.mapView(_: MapView, didReceiveEvent: MapEvent) делегата. В данном случае свойство didReceiveEvent.type имеет значение .clickOnMarker.
func MapDelegate : MapViewDelegate { func mapView ( _ map : MapView , didReceiveEvent event : String ) { // ... // Для события нажатия на маркер // event.type = .clickOnMarker // ... } } |
Кластеризация
Маркеры можно объединять в кластеры. Кластеризация создает новый источник данных на карте. Вы можете указать радиус кластеров в метрах, цвет текста и фона.
func mapViewDidLoad ( _ mapView : MapView ) { let markers : [ Marker ] = ... mapView . addCluster ( markers , id : "clusterId" , radius : 50, textColor : . white , backgroundColor : . blue ) } |
Удаление кластеров происходит с указанием идентификатора кластера.
mapView.removeCluster(id: "clusterId") |
Попапы
Для показа попапа на карте нужно указать идентификатор маркера, для которого он будет отображен, а также текст внутри попапа.
mapView.displayPopup(markerId: "marker_id_1", content: "Hello world") |
Для скрытия попапа нужно указать идентификатор маркера.
mapView.hidePopup(markerId: "marker_id_1") |
Для показа попапа после выбора маркера на карте необходимо реализовать метод mapView(_:, didSelectMarkerID:) делегата MapViewDelegate.
extension MyController : MapViewDelegate { func mapView ( _ mapView : MapView , didSelectMarkerID id : String ) { mapView . displayPopup ( id : id , content : "Hello world" ) } } |
Стили
Карта поддерживает смену стилей. Стиль .automatic означает, что карта будет автоматически менять светлый и темный стили в зависимости от настройки системной темы интерфейса.
mapView.changeStyle(.automatic) mapView.changeStyle(.dark) |
GeoJSON
Карта поддерживает отрисовку полигонов и линий из GeoJSON источника.
Добавление источника данных и отрисовка слоёв
let sourceData = Data (...)
let source = MapDataSource ( id : "sourceID" , type : . geoJSON ( sourceData )) mapView . addSource ( source ) let fillLayer = MapLayer ( id : "fillLayer" , sourceID : "sourceID" , paint : FillPaintProperties ( fillColor : . iuColor (. green ), fillOpacity : . value (0.3)) ) let strokeLayer = MapLayer ( id : "strokeLayer" , sourceID : "sourceID" , paint : LinePaintProperties () ) mapView . addLayer ( fillLayer ) mapView . addLayer ( strokeLayer ) |
Значение цвета и прозрачности можно задать в самом источнике. В таком случае используйте .source("field"), где field — имя поля в properties источника, из которого нужно брать значение. Удалить источники и слои можно с указанием их идентификаторов.
mapView.removeLayer("fillLayer")
mapView.removeLayer("strokeLayer")
mapView.removeSource("sourceID")
) |
Поддерживается отрисовка маршрутов в формате кодированной строки из сервиса Построение маршрута.
let routeSource = MapDataSource ( id : "routeSourceID" , type : . encodedString ( encodedRoute )) mapView . addSource ( routeSource ) let routeLayer = MapLayer ( id : "routeLineLayer" , sourceID : "routeSourceID" , paint : LinePaintProperties ( lineColor : . iuColor (. red ), lineWidth : 2) ) mapView . addLayer ( routeLayer ) |
Поддерживается отрисовка линий с градиентным переходом цветов на ней. Для этого необходимо включить опцию lineMetrics
у MapDataSource
, создать объект LineGradient
, указав список offset
по длине линии в диапазоне 0.0 ... 1.0 и color
hex строкой или стандартное имя цвета CSS.
let encodedRoute : String = ... let routeSourceID = "route" let routeSource = MapDataSource ( id : routeSourceID , type : . encodedString ( encodedRoute ), lineMetrics : true ) let gradient = LineGradient ( stops : [ LineGradientStop ( offset : 0, color : "#0000FF" ), LineGradientStop ( offset : 0.1, color : "royalblue" ), LineGradientStop ( offset : 0.3, color : "cyan" ), LineGradientStop ( offset : 0.5, color : "lime" ), LineGradientStop ( offset : 0.7, color : "yellow" ), LineGradientStop ( offset : 1, color : "#FF0000" ) ]) let routeLayer = MapLayer ( id : "routeLineLayer" , sourceID : routeSourceID , paint : LinePaintProperties ( lineColor : . iuColor (. green ), lineWidth : 6, lineGradient : gradient ) ) mapView . addSourcesAndLayers ( sources : [ routeSource ], layers : [ routeLayer ] ) |
Поддерживается отрисовка кругов. Поскольку GeoJSON не поддерживает круги, они симулируются полигоном с заданным количеством сторон.
mapView.addCircleSource(center: coords, radius: 500, steps: 32, id: sourceID) |
Если источники(sources) и слои(layers) известны заранее, то вы можете добавить их единым вызовом.
mapView . addSourcesAndLayers ( sources : [ source , routeSource ], layers : [ fillLayer , strokeLayer , routeLayer ] ) |
Пробки и изолинии
mapView.setLayoutVisible(true, layout: .traffic)
mapView.setLayoutVisible(true, layout: .isolines)
mapView.setLayoutVisible(true, layout: .isolinesLabel)
mapView.setLayoutVisible(true, layout: .subway)
|
Обработка ошибок
Для обработки ошибок используется метод mapView(_:, didFailWithError:) делегата MapViewDelegate.
extension MyController : MapViewDelegate { func mapView ( _ mapView : MapView , didFailWithError error : Error ) { print ( "Did fail with error: \(error.localizedDescription)" ) } } |
Геокодирование
Geocoder — компонент MapsSDK для прямого и обратного геокодирования. Для инициализации необходим API_KEY.
Пример прямого геокодирования
let geocoder = Geocoder ( apiKey : "your apiKey" ) geocoder . geocode ( query : "Ленинградский проспект 39с79" , lang : "ru" , location : Coordinates ( lng : 37.537892, lat : 55.796926) ) { result in switch result { case let . success ( response ): print ( response ) case let . failure ( error ): print ( error . localizedDescription ) } } |
SwiftUI
Для использования карты в SwiftUI предусмотрен компонент Map.
Пример использования в SwiftUI
import SwiftUI import MapsSDK class StateObject : ObservableObject { let mapConfig = MapViewConfig ( apiKey : apiKey , center : Coordinates ( lng : 37.537892, lat : 55.796926) zoomLevel : 15, style : . automatic ) let mapView = MapView () } extension StateObject : MapViewDelegate { // методы делегата } struct ContentView : View { @ StateObject private var state = StateObject () var body : some View { Map ( config : state . mapConfig , view : state . mapView , delegate : state ) } } |
Ограничения
MapsSDK может быть интегрирован в приложения с поддержкой iOS 12.4 и более поздних версий.
Начиная с iPadOS 13 у пользователей появилась возможность использовать многооконный режим. MapsSDK не был оптимизирован для работы в этом режиме.
Вы можете с легкостью интегрировать MapsSDK в приложения, основанные на фреймворках UIKit или SwiftUI.