Объекты карты

MapKit SDK позволяет отображать на карте объекты. Все объекты карты настраиваемые: вы можете создавать уникальные пользовательские сценарии с учетом потребностей разработчиков.

Метки

Добавьте пользовательские метки изображения на карту с помощью метода YMKMapObjectCollection.addPlacemark() из поля YMKMap.mapObjects.

Метод принимает YMKPoint с координатами для метки и экземпляр UIImage.

let placemark = map.mapObjects.addPlacemark()
placemark.geometry = YMKPoint(latitude: 59.935493, longitude: 30.327392)
placemark.setIconWith(UIImage(named: "icon_dollar")!)

С помощью приведенного выше кода создается экземпляр класса YMKPlacemarkMapObject, который расширяет интерфейс YMKMapObject.

Интерфейс YMKMapObject представляет каждый видимый объект на карте. Существует несколько способов настройки объектов карты: изменение видимости, разрешение перетаскивания, изменение z-индекса, настройка обработчика событий касания или перетаскивания и многое другое.

Подробнее об этом можно почитать в разделе YMKMapObject.

Настройка текста

Вы можете создавать текстовые надписи рядом с метками. Для этого используйте метод YMKPlacemarkMapObject.setTextWithText(_:).

Чтобы изменить внешний вид меток, включая их размер, цвет и положение текста относительно значка, используйте метод YMKTextStyle.

placemark.setTextWithText(
    "Special place",
    style: {
        let textStyle = YMKTextStyle()
        textStyle.size = 10.0
        textStyle.placement = .right
        textStyle.offset = 5.0
        return textStyle
    }()
)

Стили значков

Вы можете настроить представление значков меток с помощью класса YMKIconStyle. Он позволяет изменять положение привязки, размер, тип поворота, z-индекс, кликабельные области, видимость и плоскость по отношению к карте.

let iconStyle = YMKIconStyle()
iconStyle.anchor = NSValue(cgPoint: CGPoint(x: 0.5, y: 0.5))
iconStyle.scale = 0.6

let placemark = map.mapObjects.addPlacemark()
placemark.geometry = point
placemark.setIconWith(image, style: iconStyle)

Составные значки

Объедините несколько значков, чтобы создать составной.

  1. Создайте значок по умолчанию с помощью YMKMapObjectCollection.addPlacemark().

  2. Используйте YMKPlacemarkMapObject.useCompositeIcon(), чтобы создать составной значок.

  3. Используйте YMKCompositeIcon.setIconWithName(_:image:style:), чтобы добавить новый значок к составному значку.

Полный пример кода для создания составного значка:

let placemark = map.mapObjects.addPlacemark()
placemark.geometry = GeometryProvider.compositeIconPoint
placemark.addTapListener(with: singlePlacemarkTapListener)
placemark.setTextWithText(
    "Special place",
    style: {
        let textStyle = YMKTextStyle()
        textStyle.size = 10.0
        textStyle.placement = .right
        textStyle.offset = 5.0
        return textStyle
    }()
)

let compositeIcon = placemark.useCompositeIcon()
compositeIcon.setIconWithName(
    "pin",
    image: UIImage(named: "icon_dollar")!,
    style: {
        let iconStyle = YMKIconStyle()
        iconStyle.anchor = NSValue(cgPoint: CGPoint(x: 0.5, y: 1.0))
        iconStyle.scale = 0.9
        return iconStyle
    }()
)
compositeIcon.setIconWithName(
    "point",
    image: UIImage(named: "icon_circle")!,
    style: {
        let iconStyle = YMKIconStyle()
        iconStyle.anchor = NSValue(cgPoint: CGPoint(x: 0.5, y: 0.5))
        iconStyle.scale = 0.5
        iconStyle.flat = true
        return iconStyle
    }()
)

Результат:

Пример составного значка

Анимированные метки

Вы можете создать анимированную метку из анимированного PNG-файла.

  1. Создайте метку с помощью YMKMapObjectCollection.addPlacemark().

    let animatedPlacemark = pinsCollection.addPlacemark()
    animatedPlacemark.geometry = GeometryProvider.animatedImagePoint
    
  2. Используйте метод YMKPlacemarkMapObject.useAnimation() для создания объекта анимации. Задать ресурс анимации можно при помощи экземпляра YRTAnimatedImageProvider.

    let animatedImageProvider = YRTAnimatedImageProviderFactory.fromFile(
        Bundle.main.path(forResource: "animation", ofType: "png")
    ) as! YRTAnimatedImageProvider
    
    let animation = animatedPlacemark.useAnimation()
    animation.setIconWithImage(animatedImageProvider)
    
  3. Запустите анимацию, управляя ею с помощью объекта YMKPlacemarkAnimation.

    animation.play()
    

Коллекции меток

Коллекции меток используются для группировки нескольких меток в новую коллекцию вложенных объектов карты.

  1. Чтобы создать коллекцию вложенных объектов карты, используйте метод YMKMapObjectCollection.add().

    let pinsCollection = map.mapObjects.add()
    
  2. Теперь вы можете использовать новую коллекцию pinsCollection для отображения меток и других объектов карты.

    GeometryProvider.placemarkPoints.enumerated().forEach { pair in
        let point = pair.element
    
        let image = UIImage(named: "icon_dollar")!
    
        let placemark = map.mapObjects.addPlacemark()
        placemark.geometry = point
        placemark.setIconWith(image)
    
        placemark.isDraggable = true
    }
    

    Как это выглядит после добавления меток в коллекцию новых объектов карты:

    Карта с коллекцией меток

После создания коллекции pinCollection вы можете добавить в нее пины так же, как и для объектов YMKMap.mapObjects, поскольку они имеют тот же тип YMKMapObjectCollection.

Примечание

Интерфейс YMKMapObjectCollection расширяет YMKMapObject, поэтому допускается создавать вложенные коллекции и добавлять их в другие.

Все методы, имеющие интерфейс YMKMapObject, также доступны в YMKMapObjectCollection.

Вы можете итерироваться по элементам YMKMapObjectCollection, используя метод YMKBaseMapObjectCollection.traverse(with:).

Геометрии

MapKit SDK позволяет рисовать на карте примитивные геометрические объекты, такие как полигоны, полилинии и круги. Все они настраиваемые и реализуют интерфейс YMKMapObject.

Полигоны

Используйте полигон, когда вам нужно отобразить область карты для пользователей.

  1. Начните с создания экземпляра YMKPolygon.

    static let polygon: YMKPolygon = {
        var points = [
            YMKPoint(latitude: 59.935493, longitude: 30.327392),
            YMKPoint(latitude: 59.938185, longitude: 30.32808),
            YMKPoint(latitude: 59.937376, longitude: 30.33621),
            YMKPoint(latitude: 59.934517, longitude: 30.335059)
        ]
    
        points.append(points[0])
    
        let outerRing = YMKLinearRing(points: points)
    
        return YMKPolygon(outerRing: outerRing, innerRings: [])
    }()
    
  2. Используйте метод YMKMapObjectCollection.addPolygon(with:) для создания полигонального объекта карты.

    polygonMapObject = collection.addPolygon(with: GeometryProvider.polygon)
    

    После завершения сборки вы увидите полигон в стиле по умолчанию:

    Карта с полигоном по умолчанию

  3. Задайте внутренние точки при создании полигона, чтобы исключить часть внутри него.

    static let polygon: YMKPolygon = {
        var points = [
            YMKPoint(latitude: 59.935493, longitude: 30.327392),
            YMKPoint(latitude: 59.938185, longitude: 30.32808),
            YMKPoint(latitude: 59.937376, longitude: 30.33621),
            YMKPoint(latitude: 59.934517, longitude: 30.335059)
        ]
    
        points.append(points[0])
        let outerRing = YMKLinearRing(points: points)
    
        var innerPoints = [
            YMKPoint(latitude: 59.937487, longitude: 30.330034),
            YMKPoint(latitude: 59.936688, longitude: 30.33127),
            YMKPoint(latitude: 59.937116, longitude: 30.33328),
            YMKPoint(latitude: 59.937704, longitude: 30.331842)
        ]
    
        innerPoints.append(innerPoints[0])
        let innerRing = YMKLinearRing(points: innerPoints)
    
        return YMKPolygon(outerRing: outerRing, innerRings: [innerRing])
    }()
    

    Полигон с внутренними точками:

    Карта с полигоном с использованием внутренних точек

  4. Измените цвет заливки и обводки по умолчанию, используя созданный экземпляр YMKPolygonMapObject.

    polygonMapObject.strokeWidth = 1.5
    polygonMapObject.strokeColor = Palette.olive
    polygonMapObject.fillColor = Palette.oliveTransparent
    

    Карта со стилизованным полигоном

Подробнее про настройку полигонов см. в разделе YMKPolygonMapObject.

Полилинии

Полилинии часто используются для отображения маршрутов и траекторий.

  1. Создайте экземпляр YMKPolyline с искомой геометрией и добавьте на карту объект полилинейной карты с помощью метода YMKMapObjectCollection.addPolyline(with:).

    let polyline: YMKPolyline = {
        YMKPolyline(
            points: [
                YMKPoint(latitude: 59.935493, longitude: 30.327392),
                YMKPoint(latitude: 59.938185, longitude: 30.32808),
                YMKPoint(latitude: 59.937376, longitude: 30.33621),
                YMKPoint(latitude: 59.934517, longitude: 30.335059)
            ]
        )
    }()
    
    let polylineMapObject = collection.addPolyline(with: polyline)
    
  2. Настройте стили полилиний, используя переменную YMKPolylineMapObject.

    polylineMapObject.strokeWidth = 5.0
    polylineMapObject.setStrokeColorWith(.gray)
    polylineMapObject.outlineWidth = 1.0
    polylineMapObject.outlineColor = .black
    

    Результат после добавления полилинии на карту:

    Карта с добавленной полилинией

Подробнее об этом можно почитать в разделе YMKPolylineMapObject.

Круги

Круги используются для отображения круглых областей.

  1. Создайте экземпляр YMKCircle с искомой геометрией: центральной точкой и радиусом в метрах.

    var circleWithRandomRadius: YMKCircle {
        YMKCircle(center: YMKPoint(latitude: 59.935493, longitude: 30.327392), radius: 400.0)
    }
    
  2. С помощью метода YMKMapObjectCollection.addCircle(with:stroke:strokeWidth:fill:) добавьте на карту объект круга.

    let circle = pinsCollection.addCircle(with: GeometryProvider.circleWithRandomRadius)
    circle.strokeColor = Palette.red
    circle.strokeWidth = 2.0
    circle.fillColor = Palette.redTransparent
    

    Результат после добавления круга на карту:

    Карта с кругом

Подробнее о том, как настроить круговой объект карты, можно почитать в разделе YMKCircleMapObject.

Кластеры

Кластеризованные коллекции используются для отображения нескольких меток.

  1. Начните с создания YMKClusterListener с одним методом YMKClusterListener.onClusterAdded(with:), который управляет внешним видом кластера на карте.

    final class ClusterListener: NSObject, YMKClusterListener, YMKClusterTapListener {
    // MARK: - Constructor
    
    init(controller: UIViewController) {
        self.controller = controller
    }
    
    // MARK: - Public methods
    
    func onClusterTap(with cluster: YMKCluster) -> Bool {
        AlertPresenter.present(
            from: controller,
            with: "Tapped the cluster",
            message: "With \(cluster.size) items"
        )
        return true
    }
    
    func onClusterAdded(with cluster: YMKCluster) {
        let placemarks = cluster.placemarks.compactMap { $0.userData as? PlacemarkUserData }
        cluster.appearance.setViewWithView(YRTViewProvider(uiView: ClusterView(placemarks: placemarks)))
        cluster.addClusterTapListener(with: self)
    }
    
    // MARK: - Private properties
    
    private weak var controller: UIViewController?
    }
    

    Свойство YMKCluster.appearance возвращает объект YMKPlacemarkMapObject. В нашем примере мы используем метод YMKPlacemarkMapObject.setViewWithView(_:), чтобы изменить внешний вид кластера.

    ClusterView — это определяемый пользователем класс. Чтобы узнать, как он реализован, посмотрите код в нашем репозитории на GitHub.

  2. Создайте новую вложенную коллекцию с помощью метода YMKMapObjectCollection.addClusterizedPlacemarkCollection(with:).

    clusterizedCollection = collection.addClusterizedPlacemarkCollection(with: clusterListener)
    
  3. Добавьте несколько меток в новый clusterizedCollection.

    GeometryProvider.clusterizedPoints.enumerated().forEach { pair in
        let index = pair.offset
        let point = pair.element
    
        let type = PlacemarkType.random
        let image = type.image
    
        let iconStyle = YMKIconStyle()
        iconStyle.anchor = NSValue(cgPoint: CGPoint(x: 0.5, y: 0.5))
        iconStyle.scale = 0.6
    
        let placemark = clusterizedCollection.addPlacemark()
        placemark.geometry = point
        placemark.setIconWith(image, style: iconStyle)
    
        placemark.isDraggable = true
        placemark.setDragListenerWith(mapObjectDragListener)
        placemark.userData = PlacemarkUserData(name: "Data_\(index)", type: type)
        placemark.addTapListener(with: mapObjectTapListener)
    }
    
  4. Вызовите метод YMKClusterizedPlacemarkCollection.clusterPlacemarks(withClusterRadius:minZoom:). Он принимает два аргумента:

    • clusterRadius — минимальное расстояние в единицах между объектами, которые остаются в отдельных кластерах.
    • minZoom — минимальный уровень масштабирования, отображающий кластеры.
    clusterizedCollection.clusterPlacemarks(withClusterRadius: Const.clusterRadius, minZoom: Const.clusterMinZoom)
    

    Важно

    YMKClusterizedPlacemarkCollection.clusterPlacemarks(withClusterRadius:minZoom:) следует вызывать явно каждый раз, когда метки добавляются в кластеризованные коллекции или удаляются из них.

    Иначе кластеризованные метки не будут повторно отображаться.

    Кластеризованные метки с разным масштабом:

    Кластеры

Исходный код

Полные примеры кода из руководства смотрите в приложении MapObjects в нашем GitHub репозитории.