Skip to main content

Add a view annotation to a point annotation

This example shows you how to link a ViewAnnotation to a PointAnnotation and have it appear on the on a MapView using UIKit and the Mapbox Maps SDK for iOS. A ViewAnnotation is a UI pop-up that can contain text and other data that we can add to the map when the affiliated PointAnnotation receives an interaction. The view annotation(s) in this example includes a title displaying the latitude and longitude coordinates of a specified location.

Add AnnotationView class to your project

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

iOS Examples App Available

This example code is part of the Maps SDK for iOS Examples App, a working iOS project available on Github. iOS developers are encouraged to run the examples app locally to interact with this example in an emulator and explore other features of the Maps SDK.

See our Run the Maps SDK for iOS Examples App tutorial for step-by-step instructions.

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?