Maneuver instructions
The Mapbox Navigation SDK provides information about what action a driver needs to take to get from one step to the next along a route in maneuver instructions. This provides text instructions to your users at defined locations along a user's route.
The Navigation SDK uses the Mapbox Java SDK's BannerInstructions
class to hold information about the next step. The information is then used to display instructions on the device's screen. Read more about the information included in the banner instructions object in the Mapbox Directions API documentation.
Use the default maneuver UI component
The default maneuver view UI component (MapboxManeuverView
) available in the Navigation SDK holds the following pieces of information:
- Primary maneuver: Shows the name of the road, freeway, or exit of the next maneuver.
- Secondary maneuver (optional): Shows more information about the road, freeway, or exit if available.
- Sub maneuver (optional): Shows the name of the road, freeway, or exit of the maneuver after the next maneuver if it will occur shortly after completing the next maneuver.
- Lane guidance (optional): Guides the user to drive in the appropriate lane if there are multiple lanes and an upcoming maneuver requires them to be in a specific lane.
- Maneuver turn icons: It shows a maneuver turn icon associated with the maneuver.
- Step distance remaining: Shows the distance remaining to finish the current maneuver.
- Upcoming maneuver list: Shows a list of upcoming maneuvers excluding the current maneuver.
Overview one | Overview two | Overview three |
---|---|---|
1: Primary maneuver 2: Secondary maneuver 5: Maneuver icons 6: Step distance remaining 7: Upcoming maneuver list | 3: Sub maneuver | 4: Lane guidance |
Draw maneuver instructions using the Maneuver API and MapboxManeuverView
.
Add the view to the layout
Add the MapboxManeuverView
to your XML layout.
<com.mapbox.navigation.ui.maneuver.view.MapboxManeuverView
android:id="@+id/maneuverView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="4dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
Create an instance of the Maneuver API
The Maneuver API generates representation of maneuvers based on BannerInstructions
found in the DirectionsRoute
object.
You'll use several functions that belong to the Maneuver API in your activity to get the most up to date information about maneuvers and display that information in your application. Before you can access those functions, you need to create an instance of the MapboxManeuverApi
.
MapboxManeuverApi
takes a MapboxDistanceFormatter
that gives options to format the distance so you'll also have to define DistanceFormatterOptions
to pass to the API.
// Define distance formatter options
private val distanceFormatter: DistanceFormatterOptions by lazy {
DistanceFormatterOptions.Builder(this).build()
}
// Create an instance of the Maneuver API
private val maneuverApi: MapboxManeuverApi by lazy {
MapboxManeuverApi(MapboxDistanceFormatter(distanceFormatter))
}
Create an instance of the maneuver view
Once you have added the view to the XML layout file, reference it in your Activity or Fragment.
private var maneuverView: MapboxManeuverView? = null
override fun onCreate() {
...
maneuverView = findViewById(R.id.maneuverView)
}
Start and stop receiving route progress events
Once you've instantiated the Maneuver API, add the code below to start receiving route progress events.
// Listen for updates to route progress
private val routeProgressObserver = object : RouteProgressObserver {
override fun onRouteProgressChanged(routeProgress: RouteProgress) {
}
}
When using RouteProgressObserver
, you also need to register and unregister the observer in the appropriate place.
override fun onStart() {
super.onStart()
mapboxNavigation.registerRouteProgressObserver(routeProgressObserver)
}
override fun onStop() {
super.onStop()
mapboxNavigation.unregisterRouteProgressObserver(routeProgressObserver)
}
Don't forget to cancel any potential in-flight MapboxManeuverApi
requests in onStop
or onDestroy
:
override fun onDestroy() {
super.onDestroy()
maneuverApi.cancel()
}
Display primary, secondary, sub maneuver, lane guidance, and step distance
Once you have registered the RouteProgressObserver
, you need to invoke the API inside the observer to receive updated banner instruction data any time the route progress changes.
private val routeProgressObserver = object : RouteProgressObserver {
override fun onRouteProgressChanged(routeProgress: RouteProgress) {
val maneuvers = maneuverApi.getManeuvers(routeProgress, callback)
maneuverView.renderManeuvers(maneuvers)
}
}
MapboxManeuverView
uses the first item in this list to render the current maneuver and rest of the items in the list is displayed as upcoming maneuvers. The maneuver information returned does not contain data related to road shield. The data is returned in the form of Expected
, which either contains ManeuverError
or a list of Maneuver
s.
val maneuvers = maneuverApi.getManeuvers(routeProgress)
maneuverView.renderManeuvers(maneuvers)
Display road shield
After you have received the data without the road shield, if you would like to render a RoadShield
, invoke the API inside the success block to receive an updated list of Maneuver
s with the road shield data.
private val routeProgressObserver = object : RouteProgressObserver {
override fun onRouteProgressChanged(routeProgress: RouteProgress) {
val maneuvers = maneuverApi.getManeuvers(routeProgress, callback)
maneuverView.renderManeuvers(maneuvers)
maneuvers.fold(
{ error ->
// handle errors
},
{ maneuverList ->
maneuverApi.getRoadShields(maneuverList, roadShieldCallback)
}
}
}
Add the following callback that holds the information containing a list of all the maneuvers with road shields in a route leg.
private val roadShieldCallback = object : RoadShieldCallback {
override fun onRoadShields(
maneuvers: List<Maneuver>,
shields: Map<String, RoadShield?>,
errors: Map<String, RoadShieldError>
) {
maneuverView.renderManeuverShields(shields)
}
}
You should assign MapboxManeuverView
a visibility value of either GONE
or INVISIBLE
by default and change it to VISIBLE
only when the first maneuver data is available.
Customize maneuver instructions
To use a different set of colors and text properties, you can customize them in MapboxManeuverView
. The Mapbox Navigation SDK defines a custom set of properties for MapboxManeuverView
.
<declare-styleable name="MapboxManeuverView">
{/* Defines the background color of MapboxManeuverView showing the primary and secondary maneuvers as well as step distance remaining and maneuver turn icon */}
<attr name="maneuverViewBackgroundColor" format="reference|color"/>
{/* Defines the background color of MapboxManeuverView sub instructions and turn icon */}
<attr name="subManeuverViewBackgroundColor" format="reference|color"/>
{/* Defines the background color of upcoming maneuvers */}
<attr name="upcomingManeuverViewBackgroundColor" format="reference|color"/>
{/* Defines the style of maneuver arrow in the primary and sub maneuver view */}
<attr name="maneuverViewIconStyle" format="reference" />
{/* Defines the style of maneuver arrow in the lane guidance view */}
<attr name="laneGuidanceManeuverIconStyle" format="reference" />
</declare-styleable>
Change the background color
Define a custom style for MapboxManeuverView
in your styles.xml
file.
<style name="MapboxCustomManeuverStyle" parent="MapboxStyleManeuverView">
<item name="maneuverViewBackgroundColor">#058A0A</item>
<item name="subManeuverViewBackgroundColor">#046808</item>
<item name="upcomingManeuverViewBackgroundColor">#046808</item>
</style>
Then, add this style to the XML layout file where you have put your MapboxManeuverView
.
<com.mapbox.navigation.ui.maneuver.view.MapboxManeuverView
android:id="@+id/maneuverView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="4dp"
style="@style/MapboxCustomManeuverStyle"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
Example: MapboxManeuverView customization | Example: Upcoming maneuver list customization |
---|---|
Change the color of maneuver turn icons
Define a custom style for maneuver turn icons in your styles.xml
file.
<style name="MapboxCustomManeuverTurnIconStyle" parent="MapboxStyleTurnIconManeuver">
<item name="maneuverTurnIconColor">#FFEB3B</item>
<item name="maneuverTurnIconShadowColor">#7A6E03</item>
</style>
<style name="MapboxCustomManeuverStyle" parent="MapboxStyleManeuverView">
<item name="maneuverViewBackgroundColor">#058A0A</item>
<item name="subManeuverViewBackgroundColor">#046808</item>
<item name="upcomingManeuverViewBackgroundColor">#046808</item>
<item name="maneuverViewIconStyle">@style/MapboxCustomManeuverTurnIconStyle</item>
<item name="laneGuidanceManeuverIconStyle">@style/MapboxCustomManeuverTurnIconStyle</item>
</style>
Then, add this style to the XML layout file where you have put your MapboxManeuverView
.
<com.mapbox.navigation.ui.maneuver.view.MapboxManeuverView
android:id="@+id/maneuverView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="4dp"
style="@style/MapboxCustomManeuverStyle"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
Example: MapboxTurnIconManeuver icon color customization |
---|
Change the text properties
To change the textual property of primary, secondary, and sub maneuvers, define the text appearance in your styles.xml
file.
<style name="ManeuverTextAppearance" parent="TextAppearance.AppCompat">
<item name="android:textColor">#FFC107</item>
// Similarly you can add any other android text view property here
</style>
Then, invoke the API in your activity to use the style defined above.
maneuverView.updatePrimaryManeuverTextAppearance(R.style.ManeuverTextAppearance)
maneuverView.updateSecondaryManeuverTextAppearance(R.style.ManeuverTextAppearance)
maneuverView.updateSubManeuverTextAppearance(R.style.ManeuverTextAppearance)
You can use the same text appearance or can define different appearances for different levels of maneuvers.
Example: Primary & sub maneuver color customization | Example: Secondary maneuver color customization |
---|---|
Similarly you can define the text appearance for step distance remaining in your styles.xml
file and invoke the following API to change the text appearance.
maneuverView.updateStepDistanceTextAppearance(R.style.MyStepDistanceRemainingAppearance)
Example: Step distance remaining color customization |
---|
You can also change the text appearance of upcoming maneuvers in the upcoming maneuver list in your styles.xml
file.
<style name="UpcomingManeuverTextAppearance" parent="TextAppearance.AppCompat">
<item name="android:textSize">24sp</item>
// Similarly you can add any other android text view property here
</style>
Then, invoke the API in your activity to use the style defined above.
maneuverView.updateUpcomingPrimaryManeuverTextAppearance(R.style.UpcomingManeuverTextAppearance)
maneuverView.updateUpcomingSecondaryManeuverTextAppearance(R.style.UpcomingManeuverTextAppearance)
maneuverView.updateUpcomingManeuverStepDistanceTextAppearance(R.style.UpcomingManeuverTextAppearance)
Example: Upcoming maneuver list text and icon customization |
---|
All the customization options mentioned above involve interaction with MapboxManeuverView
. If you don't wish to use MapboxManeuverView
and its layout design, you can arrange the individual views in your customized layout. This allows you to decide the placement of individual views and control their appearance.
Use subviews for further customization
The maneuver view UI component, MapboxManeuverView
, includes several subviews that are also available to use directly. If you use MapboxManeuverView
in your application, you don't have to add these subviews directly, but if you want complete control over how and where the content in each subview appears in your application, you can use them directly instead of via MapboxManeuverView
. Add one or more of the following View
s to your application's layout, and use the Maneuver API to request maneuvers and render them on top of your map.
Primary maneuver
The MapboxPrimaryManeuver
view can consist of all or some of the following pieces of information:
- Exit number
- Text containing the road name
- Road shield containing the name and optional shield icon
MapboxPrimaryManeuver
will be included using default configuration and displaying data from the BannerInstructions.primary()
field.
Example: Road shield and text | Example: Exit number and text |
---|---|
Secondary maneuver
The MapboxSecondaryManeuver
view provides additional context to the primary maneuver element. The content included in the secondary maneuver can consist of all or some of the following pieces of information:
- Exit number
- Text containing the road name
- Road shield containing the name and optional shield icon
MapboxSecondaryManeuver
will be included using default configuration and displaying data from the BannerInstructions.secondary()
field.
Example: Text containing road name |
---|
Sub maneuver
The MapboxSubManeuver
view provides a preview of the maneuver that is coming up next after the one described in the primary maneuver. The component will only show a sub maneuver if the next maneuver will occur shortly after completing the primary maneuver. The content in the sub maneuver can consist of all or some of the following pieces of information:
- Exit number
- Text containing the road name
- Road shield containing the name and optional shield icon
MapboxSubManeuver
will be included using default configuration and displaying data from the BannerInstructions.sub()
field of the type text.
Example: Road shield and text |
---|
BannerInstructions.sub
, both of these cannot exist at the same time. If lane information is available, that takes precedence over information about the next maneuver.Lane guidance
The MapboxLaneGuidanceAdapter
and MapboxLaneGuidance
views describe the available turn lanes at an intersection and guides the user to drive in the appropriate lane if the upcoming maneuver requires them to be in a specific lane. Lane guidance turn lane indicators are provided in the order they appear on the street, from left to right.
MapboxLaneGuidanceAdapter
and MapboxLaneGuidance
will be included using default configuration and displaying data from the BannerInstructions.sub()
field of the type lane.
Example: Turn lanes |
---|
BannerInstructions.sub
, both of these cannot exist at the same time. If lane information is available, that takes precedence over information about the next maneuver.Maneuver turn icons
The MapboxTurnIconManeuver
view is used to provide visual clues about turn direction to the text associated with primary and sub maneuver instructions. These icons are displayed in conjunction with MapboxPrimaryManeuver
and MapboxSubManeuver
.
MapboxTurnIconManeuver
will be included using default configuration and displaying data from the BannerInstructions.primary().modifier()
and BannerInstructions.sub().modifier()
field.
Example: Maneuver icon |
---|
Step distance
The MapboxStepDistance
view provides additional context to the primary maneuver. It denotes the distance remaining to finish the current step or before the beginning of next maneuver or the total step distance for the upcoming maneuver. It makes use of appropriate formatting classes to format the distance value in miles (mi) or kilometers (km) based on the geography.
MapboxStepDistance
will be included using default configuration and displaying data from the RouteStepProgress.distanceRemaining()
field, which is obtained from RouteProgress
.
Example: Step distance remaining in miles |
---|
Upcoming maneuver list
The MapboxUpcomingManeuverAdapter
view shows all the maneuvers between the current maneuver and the destination. Each upcoming maneuver in the list contains the following sub views:
MapboxStepDistance
: Total step distance of this maneuverMapboxTurnIconManeuver
: Maneuver turn iconMapboxPrimaryManeuver
: Primary maneuverMapboxSecondaryManeuver
: Secondary maneuver
MapboxUpcomingManeuverAdapter
will be included using default configuration and displaying data from the RouteLeg.steps()
field.
Example: Upcoming maneuver list |
---|