Skip to main content

Add a view annotation to a point annotation

This UIKit example shows you how to link a ViewAnnotation to a pointAnnotation and have it appear on the on a MapView. A ViewAnnotation is a UI pop-up that can contain text and other data that we can spawn on the MapView when the affiliated pointAnnotation receives an interaction.

In this example, we spawn the ViewAnnotation at a specified lat and long based on the location of the pointAnnotation when the user clicks on the pointAnnotation icon on your map. Data from the pointAnnotation is then fed to the ViewAnnotation and shown in the pop-up, containing more information about the selected point-of-interest.

Add AnnotationView class to your project

This example uses AnnotationView, a custom class defined in the Maps SDK for the iOS Examples App. To use this code snippet, you must also add the AnnotationView class to your project.

ViewAnnotationWithPointAnnotationExample.swift
import UIKit
import MapboxMaps
import CoreLocation

final class ViewController: UIViewController {
private var mapView: MapView!
private var pointAnnotationManager: PointAnnotationManager!
private var cancelables = Set<AnyCancelable>()
private var annotation: ViewAnnotation?

private let image = UIImage(named: "intermediate-pin")!
private lazy var markerHeight: CGFloat = image.size.height

override func viewDidLoad() {
super.viewDidLoad()

let centerCoordinate = CLLocationCoordinate2D(latitude: 39.7128, longitude: -75.0060)
let options = MapInitOptions(cameraOptions: CameraOptions(center: centerCoordinate, zoom: 7))

mapView = MapView(frame: view.bounds, mapInitOptions: options)
mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
view.addSubview(mapView)

pointAnnotationManager = mapView.annotations.makePointAnnotationManager()

mapView.mapboxMap.onMapLoaded.observeNext { [weak self] _ in
guard let self = self else { return }

try? self.mapView.mapboxMap.addImage(self.image, id: Constants.blueIconId)
self.addPointAndViewAnnotation(at: self.mapView.mapboxMap.coordinate(for: self.mapView.center))



}.store(in: &cancelables)

mapView.gestures.onMapTap.observe { [weak self] context in
if let self, self.annotation == nil {
self.addViewAnnotation(at: context.coordinate)
}
}.store(in: &cancelables)

mapView.mapboxMap.styleURI = .streets
}

// MARK: - Annotation management

private func addPointAndViewAnnotation(at coordinate: CLLocationCoordinate2D) {
addPointAnnotation(at: coordinate)
addViewAnnotation(at: coordinate)
}

private func addPointAnnotation(at coordinate: CLLocationCoordinate2D) {
var pointAnnotation = PointAnnotation(id: Constants.markerId, coordinate: coordinate)
pointAnnotation.iconImage = Constants.blueIconId
pointAnnotation.iconAnchor = .bottom
pointAnnotation.iconOffset = [0, 12]

pointAnnotationManager.annotations.append(pointAnnotation)
}

// Add a view annotation at a specified location and optionally bind it to an ID of a marker
private func addViewAnnotation(at coordinate: CLLocationCoordinate2D) {
let annotationView = AnnotationView(frame: CGRect(x: 0, y: 0, width: 128, height: 64))
annotationView.title = String(format: "lat=%.2f\nlon=%.2f", coordinate.latitude, coordinate.longitude)
let annotation = ViewAnnotation(
annotatedFeature: .layerFeature(layerId: pointAnnotationManager.layerId, featureId: Constants.markerId),
view: annotationView)
annotation.variableAnchors = [ViewAnnotationAnchorConfig(anchor: .bottom, offsetY: markerHeight - 12)]
annotationView.onClose = { [weak self, weak annotation] in
annotation?.remove()
self?.annotation = nil
}
annotationView.onSelect = { [weak annotation] selected in
annotation?.selected = selected
annotation?.setNeedsUpdateSize()
}
self.annotation = annotation

mapView.viewAnnotations.add(annotation)
}
}

extension ViewController {
private enum Constants {
static let blueIconId = "blue"
static let markerId = UUID().uuidString
}
}
Was this example helpful?