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.
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.
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
}
}