Skip to main content

View annotations

Add a regular Android View bound to some Geometry on top of the Mapbox MapView using the View Annotations API. This can be helpful to display an info window when a point is tapped or add a label on top of a linestring or a polygon.

Benefits:

  • Adding Android View as a view annotation allows to add clickable buttons or any other Android UI elements.
  • View annotations bound to complex geometries (line, polygon) are positioned dynamically and stay within the camera viewport if possible.
  • High rendering performance when using 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:

  • Performance may be an issue when adding many view annotations (> 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.

Create a view annotation

To create a view annotation a few things are required:

  • An Android view represented as either an XML layout that will be inflated by the view annotation manager or a View prepared beforehand.
  • A ViewAnnotationManager instance.

Create a layout

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>

Add a view annotation to 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)
}
)
}

private fun addViewAnnotationToAnnotatedLayerFeature(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 feature with `FEATURE_ID` from layer with `LAYER_ID`
annotatedLayerFeature(LAYER_ID) {
featureId(FEATURE_ID)
}
}
)
}
More view annotation options
There are many more options available when adding or updating the view annotation. See the complete list of options in the ViewAnnotationOptions documentation.

Customize 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:

viewAnnotationManager.updateViewAnnotation(
existingViewAnnotation,
viewAnnotationOptions {
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.

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:

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 the 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

Attach to the layer feature

To attach the view annotation to the layer feature, ViewAnnotationOptions.annotatedFeature of type AnnotatedLayerFeature should be used. Specify the Feature to attach view annotation with the
feature id and the layer 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.

Below you can find examples of a view annotation attached to a point layer and a line layer.

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

Attach to a point annotation by the layer/feature id

This shows marker pop-up window attached to a point with minimal amount of code :

// 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

Attach to a line annotation by the layer/feature id

This shows marker pop-up window attached to a polyline with minimal amount of code:

// add polyline annotation
val annotationPlugin = mapView.annotations
val annotationOptions: PolylineAnnotationOptions = PolylineAnnotationOptions()
.withPoints(listOf(POINT_SRC, POINT_DST))
.withLineWidth(10.0)
val annotationManager = annotationPlugin.createPolylineAnnotationManager(AnnotationConfig(layerId = LAYER_ID))
val annotation = annotationManager.create(annotationOptions)

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

Add view annotation anchored to a symbol layer feature

Was this page helpful?