Skip to main content

View annotations

Add view annotations on top of the map view using the Mapbox Maps SDK's View Annotations API. View annotations are UIKit views that the SDK draws on top of a Mapbox MapView and can be bound to a Geometry or to a feature rendered on a Layer. This can be helpful for achieving common patterns used in maps in mobile applications such as showing an information window when tapping a point of interest (POI), or providing estimated time of arrival (ETA) for navigation purposes along a route.

Supported Layer types

Currently the following Layer types are supported:- LineLayer- FillLayer- FillExtrusionLayer- CircleLayer- SymbolLayer

Benefits:

  • Straight-forward API that allows adding an iOS UIView as a view annotation, making it possible to add clickable buttons or any other UI elements.
  • High rendering performance when using a reasonable number of views (generally below 100, but may vary based on the view's content and the user's device model).
  • Wide number of options including allowing overlap between view annotations, selected state, connecting to a map feature, and more.

Limitations:

  • Inefficient and poor performance when adding many features (> 250) to the map if allow overlap is turned on.

Create a view annotation

Create a UIView

Start by creating a new UIView or subclass of UIView that contains the contents of the view annotation. This can include anything from text to images to interactive elements and more.

For example, to create a minimal UIView containing text:

private func createSampleView(withText text: String) -> UILabel {
let label = UILabel()
label.text = text
label.font = .systemFont(ofSize: 14)
label.numberOfLines = 0
label.textColor = .black
label.backgroundColor = .white
label.textAlignment = .center
return label
}

Add a view annotation to the MapView

To add the view annotation on top of the MapView, start by:

  1. Creating and configuring a ViewAnnotation with the sample view from above.
  2. Passing the sample view and options to the map view.

Add the view annotation on view load:

override func viewDidLoad() {
super.viewDidLoad()
// Define a coordinate
let centerCoordinate = CLLocationCoordinate2D(latitude: 39.7128, longitude: -75.0060)
// Add a map view
let options = MapInitOptions(cameraOptions: CameraOptions(center: centerCoordinate, zoom: 7))
mapView = MapView(frame: view.bounds, mapInitOptions: options)
mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
view.addSubview(mapView)
// Add the view annotation
let viewAnnotation = ViewAnnotation(coordinate: centerCoordinate, view: createSampleView(withText: "Hello world!"))
mapView.viewAnnotations.add(viewAnnotation)
}

In SwiftUI you may achieve the similar behavior using MapViewAnnotation and SwiftUI.Text instead of creating UILabel

let centerCoordinate = CLLocationCoordinate2D(latitude: 39.7128, longitude: -75.0060)
Map(initialViewport: .camera(center: centerCoordinate, zoom: 7)) {
Map(initialViewport: .camera(center: .apple, zoom: 10)) {
MapViewAnnotation(coordinate: .apple) {
Text("Hello world!")
.font(.system(size: 14))
.lineLimit(0)
.foregroundColor(.black)
.multilineTextAlignment(.center)
.background(Color.white)
}
.selected(true) // To bring a view annotation on top of others regardless of the order in which it was added
}
}
More view annotation options

There are many more options available when adding or updating the view annotation. See the complete list of options in theViewAnnotation documentation.

Customize the appearance

Specify order

The z-index of view annotations is based on the order in which they are added. This allows you to control which view is visible when multiple views intersect on the screen.

To bring a view annotation on top of others regardless of the order in which it was added, use the selected property:

viewAnnotation.selected = true

Any number of view annotations could be in selected state. The z-index among selected view annotations also respects the order in which they are added.

Default order
View annotations with z-index based on the order in which they were added: Hello world!, Прывітанне Сусвет!, Hallo Welt!, Hei maailma!
Override order
Use the selected property to bring the Hello world! annotation on top of others regardless of the order in which they were added.

View annotations do not rotate, pitch, or scale with the map, but some properties (including width, height, and additional offset in pixels) can be controlled by the user using ViewAnnotationAnchorConfig. You can provide multiple anchor configurations for an annotation, map renderer will automatically pick the first suitable anchor position depending on position relative to other view annotations or its annotated feature on the map, and notifies the change of anchor using ViewAnnotation/onAnchorChanged.

@State selectedAnchor: ViewAnnotationAnchorConfig?

Map() {
MapViewAnnotation(coordinate: .apple) { EmptyView() }
.variableAnchors([
ViewAnnotationAnchorConfig(anchor: .top, offsetX: 10, offsetY: 10),
ViewAnnotationAnchorConfig(anchor: .bottom)
])
.onAnchorChanged { config in
selectedAnchor = config
}
}

Handle visibility

When a view annotation is added or updated, visibility can be specified explicitly. An annotation becomes hidden when it goes out of map view’s bounds or visible property is changed. You can listen to the event when the annotation's visibility has changed using ViewAnnotation/onVisibilityChanged.

viewAnnotation.visible = false
viewAnnotation.onVisibilityChanged = { isVisible in
// Handle visibility changes here
}
Do not modify the UIView's isHidden property

Do not change the UIView's isHidden property directly. When setting visible to false, it will set the view to hidden and also remove it from the layout calculation.

Handle content size updates

You do not need to explicitly set size for a view annotation, however, when you do some operation that results in content size changed, you should call ViewAnnotation/setNeedsUpdateSize() to update the annotation size.

updateViewSize(width: 100, height: 100)
viewAnnotation.setNeedsUpdateSize() // Updates the annotation size.

Common uses

The flexibility of view annotations means that there are countless ways to use this feature, but there are a few common uses outlined below to help you get started.

Display on map click

You can add view annotations when a user interacts with the map.

When the user clicks on the map, you can get information from the map camera, position (like in the example linked below), or data in the map to determine the contents of the view annotation using one of MapboxMap's map feature query methods.

EXAMPLE
Add view annotations

Add view annotation on a map click.

Attach to a geometry

You can tie a view annotation to a geometry, for example, a line string, this allows the annotation to stay visible on screen along with the visible part of the line string.

EXAMPLE
Dynamic view annotations

Use Dynamic View Annotations, Style, and Viewport API to create navigation experience

Attach to an annotated feature

You can tie a view annotation's visibility to an annotated feature's visibility using AnnotatedFeature. This allows implementing marker pop-ups with a minimal amount of code and makes the view annotation disappear automatically if the point annotation image is not visible due to overlap or collision.

Map() {
PointAnnotation(id: "some-id", coordinate: coordinate)
.iconImage("marker-image-name")
.iconAnchor(.bottom)

MapViewAnnotation(layerId: "some-id") { Text("Annotation view") }
.variableAnchors([
ViewAnnotationAnchorConfig(anchor: .bottom, offsetY: markerImageHeight)
])
}
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.

EXAMPLE
View annotations: attach to a point annotation

Add view annotation anchored to a point annotation.

Note

While the View Annotation API does not come with built-in logic for handling opening and closing a callout attached to a symbol layer feature when the feature is click, you can see one possible way to implement that functionality in the Add view annotations connected to features.

EXAMPLE
Add view annotations connected to features

Add view annotation anchored to a symbol layer feature.

Was this page helpful?