Route arrow

The Navigation SDK allows you to display an arrow on a map that illustrates the next maneuver as a user navigates along a route. This is a common UI component used in turn-by-turn navigation applications.

Use the route maneuver arrow UI component

The route maneuver arrow UI component consists of two main classes:

By default the route maneuver arrow will be displayed as a white arrow on top of the route line (if it exists) or on top of all features in the map. It will be visible for the maneuver that is next based on the device location.

Instantiate the route maneuver arrow API

Instantiate the MapboxRouteArrowApi and MapboxRouteArrowView classes in your Activity or Fragment.

val routeArrow = MapboxRouteArrowApi()
val routeArrowOptions = RouteArrowOptions.Builder(context).build()
val routeArrowView = MapboxRouteArrowView(routeArrowOptions)

To show the next maneuver arrow, register a RouteProgressObserver with MapboxNavigation. When a RouteProgress object is received, call the MapboxRouteArrowApi and pass the result of the arrow calculation to the render method of MapboxRouteArrowView.

private val routeProgressObserver = object : RouteProgressObserver {
    override fun onRouteProgressChanged(routeProgress: RouteProgress) {
        val updatedManeuverArrow = routeArrow.addUpcomingManeuverArrow(routeProgress)
        routeArrowView.renderManeuverUpdate(mapStyle, updatedManeuverArrow)
    }
}

Be sure to always unregister observers in onStop() or onDestroy().

Customize the route maneuver arrow

There are several ways to customize the route maneuver arrow UI component using RouteArrowOptions.

Position the route arrow relative to map layers

The map on which you are displaying your route line contains many individual layers (for example, roads, buildings, labels, and more). The route maneuver arrow UI component consists of layers that are added to the map.

If you're using the route line UI component and it exists at the time the maneuver arrow is initialized, the maneuver arrow layers will be placed above the route line's traffic layer. If the route line's traffic layer doesn't exist or hasn't been created yet, the maneuver arrow will be placed on top of all the other layers in the map.

Position the route line relative to map layers

You can read more about the default position of route line layers relative to other map layers and options for cusomtization in the Route line guide.

On top of all layers in the map is not always the most optimal position for a route arrow because it may appear on top of road labels and other labels on the map. You can specify the route line layer's veritcal position within all map layers using the aboveLayerId parameter of the RouteArrowOptions. When the maneuver arrow layers are created they will be placed above the layer specified by the aboveLayerId option.

val routeArrowOptions = RouteArrowOptions.Builder(this)
    .withAboveLayerId("someLayerId")
    .build()

Add custom arrows

The Navigation SDK supports displaying multiple arrows on the map. An arrow is defined by a collection of at least two Point objects. The arrowhead is placed at the last point in the collection and the direction of the arrowhead is determined by calculating the bearing of the last two points in the collection.

Arrows can be added to and removed from the map before and during navigation. While the next maneuver arrow is managed by the MapboxRouteArrowApi class, it is up to you to manage any other arrows you add to the map.

To add a custom arrow, create an arrow using ManeuverArrow and add it to the view.

val myArrow = ManeuverArrow(
                listOf(
                Point.fromLngLat(-122.432034, 37.775755),
                Point.fromLngLat(-122.431229, 37.775865),
                Point.fromLngLat(-122.431293, 37.776255)
                )
            )
            
val result = mapboxArrowApi.addArrow(myArrow)
routeArrowView.render(style, result)    

To remove an arrow you've previously added:

val result = mapboxArrowApi.removeArrow(myArrow)
routeArrowView.render(style, result)