Skip to main content

View annotations

View annotations are Android Views that the SDK draws on top of a Mapbox MapView. They 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

The following layer types are supported for binding a view annotation to a feature:

Looking for a simpler option?

If you need basic pin-style markers in Jetpack Compose, consider using Markers instead. Markers provide a quick way to add default-styled markers with minimal code. Use View Annotations when you need completely custom UI elements or complex layouts.

Benefits:

  • Straight-forward API that allows adding an Android View as a view annotation, integrating with your existing Android UI code.
  • 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.
  • Low-level API that requires adding code on the user's end for advanced cases.
  • No built-in support for clustering

Create a view annotation

Start by creating a new layout that contains the contents of the view annotation. This can include anything from text to images to interactive elements.

For example, to create a minimal layout containing text:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="100dp"
android:layout_height="60dp"
android:background="@android:color/white"
xmlns:app="http://schemas.android.com/apk/res-auto">

<TextView
android:id="@+id/annotation"
android:text="hello world"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:textSize="20sp"
android:padding="3dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

To add the view annotation on top of the MapView, start by getting a ViewAnnotationManager instance:

val viewAnnotationManager = binding.mapView.viewAnnotationManager

Then use the manager's addViewAnnotation method to create the view annotation. Three overloaded methods are available:

  1. Taking a View that is already inflated.
  2. Taking an XML identifier resId and returning a synchronously inflated View.
  3. Taking an XML identifier resId and returning an inflated View in asyncInflateCallback. If using this method, you must add async inflater dependency to your project explicitly (any 1.x.x version should work).

All methods above also require ViewAnnotationOptions with at least annotatedFeature field specified. AnnotatedFeature can be either a direct Geometry instance or a LayerFeature. The latter allows to bind the view annotation to the specific feature on the map, and to update the view annotation with the feature automatically. ViewAnnotationOptions.geometry and ViewAnnotationOptions.annotatedLayerFeature extension functions are available in Kotlin to simplify the annotatedFeature setting.

You can also specify other options for the view annotation within viewAnnotationOptions.

private fun addViewAnnotationToPoint(point: Point) {
// Define the view annotation
val viewAnnotation = viewAnnotationManager.addViewAnnotation(
// Specify the layout resource id
resId = R.layout.annotation_view,
// Set any view annotation options
options = viewAnnotationOptions {
// View annotation is placed at the specific geo coordinate
geometry(point)
}
)
}
More view annotation options

There are many more options available when adding or updating the view annotation. See the complete list of options in theViewAnnotationOptions 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 priority property:

// specify the priority when inserting a new view annotation
val newViewAnnotation = viewAnnotationManager.addViewAnnotation(
resId = R.layout.some_layout,
options = viewAnnotationOptions {
geometry(point)
priority(10)
}
)

// update an existing view annotation's priority
viewAnnotationManager.updateViewAnnotation(
existingViewAnnotation,
viewAnnotationOptions {
priority(10)
}
)
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 priority property to bring the Hello world! annotation on top of others regardless of the order in which they were added.

Control anchor

To update the anchor position and the offset of the view annotation you can specify single or multiple anchors. When you set multiple anchors, the system uses the first one that fits the view annotation within the viewport:

// set single anchor
viewAnnotationManager.updateViewAnnotation(
existingViewAnnotation,
viewAnnotationOptions {
annotationAnchor {
// bottom of the view annotation is placed on the geometry
anchor(ViewAnnotationAnchor.BOTTOM)
offsetX(-10.0)
offsetY(20.0)
}
}
)

// set multiple anchors
viewAnnotationManager.updateViewAnnotation(
existingViewAnnotation,
viewAnnotationOptions {
annotationAnchors(
{
anchor(ViewAnnotationAnchor.TOP_RIGHT)
},
{
anchor(ViewAnnotationAnchor.TOP_LEFT)
},
{
anchor(ViewAnnotationAnchor.BOTTOM_RIGHT)
},
)
}
)

Handle visibility

When a view annotation is added or updated, visibility can be specified explicitly:

viewAnnotationManager.addViewAnnotation(
R.layout.some_layout,
viewAnnotationOptions {
geometry(point)
// hide view annotation initially, even if the android view is visible
visible(false)
}
)

For most use cases there is no need to specify visibility for viewAnnotationOptions explicitly. Instead, you can update the visibility of the actual view, or guard the ViewAnnotation composable function with a condition:

val view = viewAnnotationManager.addViewAnnotation(
// Inflated view is visible by default
R.layout.some_layout,
viewAnnotationOptions {
// Do not set visibility explicitly
geometry(point)
}
)
// Simply hide the view when needed
view.visibility = View.GONE

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
View annotations: basic example

Add view annotation to the map

EXAMPLE
(Compose) View annotations: basic example

Show view annotations on a map

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.

Dynamic view annotations

When a view annotation is added to the complex geometry (for example, line or polygon), it becomes dynamic and is displayed at some coordinate belonging to the geometry. It updates its position automatically if the camera viewport changes and the view annotation is going out of the visible scope.

EXAMPLE
Dynamic view annotations

Add several dynamic view annotations to line and polygon features

EXAMPLE
(Compose) Dynamic view annotations

Add several dynamic view annotations to line and polygon features

Attach to an existing map feature

You can tie a view annotation's visibility to another feature on the map using the layer/feature id. For example, you can position a ViewAnnotation relative to a point feature in a SymbolLayer to make a marker pop-up. You could also use a line or polygon feature to show additional information about that feature when it is visible.

To attach the view annotation to the layer feature, use ViewAnnotationOptions.annotatedFeature and specify the feature to use by its layer id and feature id.

The visibility of the feature will then determine the visibility of the view annotation. For example, if the feature collides with another feature, the associated view annotation will also disappear.

// add point annotation
val annotationPlugin = mapView.annotations
val pointAnnotationOptions: PointAnnotationOptions = PointAnnotationOptions()
.withPoint(POINT)
.withIconImage(iconBitmap)
.withIconAnchor(IconAnchor.BOTTOM)
val pointAnnotationManager = annotationPlugin.createPointAnnotationManager(AnnotationConfig(layerId = LAYER_ID))
val pointAnnotation = pointAnnotationManager.create(pointAnnotationOptions)

val viewAnnotationManager = mapView.viewAnnotationManager
// add view annotation attached to the point
val viewAnnotation = viewAnnotationManager.addViewAnnotation(
resId = R.layout.item_callout_view,
options = viewAnnotationOptions {
annotatedLayerFeature(LAYER_ID) {
featureId(annotation.id)
}
}
)
EXAMPLE
View annotations: attach to a point annotation

Add view annotation anchored to a point annotation and update its position when point annotation is dragging

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 View annotations: advanced example.

EXAMPLE
View annotations: advanced example

Add view annotation anchored to a symbol layer feature

Was this page helpful?