User interface
The Navigation SDK provides several pre-built UI components that you can use to build a complete user interface for a turn-by-turn navigation application. Drop components into your application using their default configuration or customize the components' behavior and appearance to create a completely unique experience for your users.
Use the drop-in UI
The Navigation SDK for iOS offers a complete drop-in UI, NavigationViewController
.
NavigationViewController
embeds a NavigationView
that contains the following UI components with appropriate functionality included by default:
InstructionsBannerView
: Maneuver instructionsInformationStackView
: Additional maneuver instructions informationBottomBannerViewController
: Trip progressResumeButton
: Resume buttonWayNameLabel
: Label for current wayFloatingStackView
: Camera, volume, and feedback buttonsNavigationMapView
: Map a displaying route line and user locationSpeedLimitView
: Speed limit
+--------------------+
| 1 |
+--------------------+
| 2 |
+---+------------+---+
| 8 | | |
+---+ | 6 |
| | |
| 7 +---+
| |
| |
| |
+------------+ |
| 4 || 5 | |
+------------+-------+
| 3 |
+--------------------+
Present a navigation view controller
- You need to request navigation routes before presenting the
NavigationViewController
instance:
let mapboxNavigationProvider = MapboxNavigationProvider(coreConfig: .init())
let mapboxNavigation = navigationProvider.mapboxNavigation
let routingProvider = mapboxNavigation.routingProvider()
let navigationRoutes = try await routingProvider.calculateRoutes(options: routeOptions).value
- Specify the options for the
NavigationViewController
let navigationOptions = NavigationOptions(
mapboxNavigation: mapboxNavigation,
voiceController: mapboxNavigationProvider.routeVoiceController,
eventsManager: mapboxNavigationProvider.eventsManager()
)
- Pass the requested routes and the specified options into the
NavigationViewController
initializer:
let navigationViewController = NavigationViewController(
navigationRoutes: navigationRoutes,
navigationOptions: navigationOptions
)
- Present the
NavigationViewController
as a usualUIViewController
, e.g.:
navigationViewController.modalPresentationStyle = .fullScreen
self.present(navigationViewController, animated: true)
Maneuver instructions
NavigationViewController
uses logic from Mapbox Core Navigation to trigger a comprehensive system of visual and spoken instructions by default. There are default styling rules for visual instructions and default settings for voice instructions. Instructions can be customized to synchronize your application's behavior with instructions coming from the Mapbox Navigation SDK and customizing the style of visual instructions to fit with your application.
Default visual instructions
The default TopBannerViewController
UI component shows maneuver instructions. It is refreshed by route progress events and displays the following pieces of information:
- Primary visual instruction: Shows the name of the road, freeway, or exit of the next maneuver.
- Secondary visual instruction (optional): Shows more information about the road, freeway, or exit if available.
- Tertiary visual instruction (optional): Shows either 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, or 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.
- Quaternary visual instruction (optional): In some regions, a graphical representation of the layout of a freeway exit.
- Upcoming maneuver list: Shows a list of upcoming maneuvers excluding the current maneuver.
A user can also tap or swipe down on TopBannerViewController
to view a full list of maneuvers for the trip.
Listen for changes to visual instructions
By default, visual instructions will be displayed when NavigationComponent.onDidPassVisualInstructionPoint(_:)
is called and mapboxNavigation.navigation().bannerInstructions
posts when the user passes the appropriate point at which to display a visual instruction. A visual instruction point occurs near the beginning of a step. There may be additional visual instruction points along the step as additional information, like turn lanes, becomes relevant.
You can use VisualInstructionDelegate.label(_:willPresent:as:)
to adjust the predefined contents of visual instruction provided by the Directions API, but you cannot currently trigger an arbitrary message outside the visual instructions that are triggered by default.
func label(_ label: InstructionLabel, willPresent instruction: VisualInstruction, as presented: NSAttributedString) -> NSAttributedString? {
let range = NSRange(location: 0, length: presented.length)
let mutable = NSMutableAttributedString(attributedString: presented)
mutable.mutableString.applyTransform(.latinToKatakana, reverse: false, range: range, updatedRange: nil)
return mutable
}
Listen for changes to spoken instructions
By default, spoken instructions will be played when mapboxNavigation.navigation().voiceInstructions
posts an event that the user passes the appropriate point at which to announce a spoken instruction. A spoken instruction point occurs near the end of a step. There may be additional spoken instruction points, as time allows, at a comfortable distance before the end of the step and near the beginning of the step. A single spoken instruction point may correspond to an instruction about two successive maneuvers nearby.
You can also trigger arbitrary voice instructions by calling SpeechSynthesizing.speak(_:during:locale:)
.
For more information on supported SSML tags see Amazon's SSML Tags Supported by Amazon Polly guide.
Spoken instruction override
Provide a custom SpeechSynthesizing
implementation to override a spoken instruction with a custom instruction.
class CustomSpeechSynthesizer: SpeechSynthesizing {
// provide custom speech implementation
}
...
let customSpeechSynthesizer = CustomSpeechSynthesizer()
let mapboxNavigationProvider = MapboxNavigationProvider(
coreConfig: .init(ttsConfig: .custom(speechSynthesizer: customSpeechSynthesizer))
)
let navigationOptions = NavigationOptions(
mapboxNavigation: mapboxNavigation,
voiceController: mapboxNavigationProvider.routeVoiceController,
eventsManager: mapboxNavigationProvider.eventsManager()
)
let navigationViewController = NavigationViewController(
navigationRoutes: navigationRoutes,
navigationOptions: navigationOptions
)
Trip progress
Many navigation applications display data related to trip progress including the estimated time to arrival and the distance remaining. NavigationViewController
includes a trip progress UI. The SDK uses the RouteProgress
class to hold information about your user's progress along a route. The information is then used to display indicators of trip progress on the device's screen. Read more about the information included in the route progress object in the Route progress guide.
The default BottomBannerViewController
UI component illustrates the user's progress along a route. It is refreshed by route progress events and displays:
- Estimated time to arrival
- Distance remaining
- Estimated time remaining
Map
While applications using the Navigation SDK don't have to include a map, many use cases will require maps to provide an appropriate navigation experience to your users. By default, NavigationViewController
uses the Mapbox Maps SDK for iOS to display routes on a map and show the user's location on the map throughout their trip to provide both navigation-related context and nearby places that may be of interest to the driver.
Read more about using maps in the Maps for navigation guide.
Speed limit
The speed limit UI included in NavigationViewController
, SpeedLimitView
, displays the speed limit of the road the user is currently traveling on.
Map buttons
NavigationViewController
includes several buttons for the user to control the behavior of the application including:
Function | Button | Description |
---|---|---|
Route overview | Zoom out to an overview of the full route at any time during navigation. | |
Resume navigation | Zoom back in to the current location after viewing the route overview or after panning around the map manually. | |
Volume control | Mute or unmute voice instructions. | |
Feedback | Provide route or map feedback. |
Customize NavigationViewController
App styling
When using NavigationViewController
, it's possible to apply custom fonts and colors to various parts of the UI. The easiest way to find elements and their class name to style is to use the Debug View Hierarchy feature in Xcode.
- While running your app, select the Debug View Hierarchy button.
- Select the view you wish to style.
- On the right side of your screen, note the class name.
- Apply your styling:
DistanceLabel.appearance(for: traitCollection, whenContainedInInstancesOf: [InstructionsBannerView.self]).unitTextColor = .red
DistanceLabel.appearance(for: traitCollection, whenContainedInInstancesOf: [InstructionsBannerView.self]).unitTextColor = .green
Remember to apply such styling in Style.apply()
method.
It is also helpful to view the default styling applied by the StandardDayStyle
.
Language
For customizing the language used in visual and spoken instructions, see Localization and internationalization.
Build a custom UI
If you want to build a completely customizable turn-by-turn experience, you can use some of the Navigation SDK's UI components used in NavigationViewController
individually or build your own components from scratch.
Bottom banner
When using NavigationViewController
, you can replace the default BottomBannerViewController
that shows trip progress with a custom view that shows trip progress or anything else you'd like to occupy the bottom banner position.
Start by creating your custom view:
class CustomBottomBarViewController: ContainerViewController, CustomBottomBannerViewDelegate {
// build custom view
}
Then pass your custom implementations of the bottom banner to NavigationOptions
. If you do not specify a bottomBanner
explicitly, the default BottomBannerViewController
will be used by default.
let bottomBanner = CustomBottomBarViewController()
let navigationOptions = NavigationOptions(
mapboxNavigation: mapboxNavigation,
voiceController: mapboxNavigationProvider.routeVoiceController,
eventsManager: mapboxNavigationProvider.eventsManager(),
bottomBanner: bottomBanner
)
let navigationViewController = NavigationViewController(
navigationRoutes: navigationRoutes,
navigationOptions: navigationOptions
)
bottomBanner.navigationViewController = navigationViewController
Substitute the default top and bottom banners with custom view controllers.
Top banner
You can replace the default TopBannerViewController
with a custom view that shows anything you'd like to occupy the top banner position. Create your custom view:
class CustomTopBannerViewController: ContainerViewController, CustomBottomBannerViewDelegate { // build custom view}
Then pass your custom implementations of the top banner to NavigationOptions
. If you do not specify a topBanner
explicitly, the default TopBannerViewController
will be used by default.
let topBanner = CustomTopBannerViewController()
let navigationOptions = NavigationOptions(
mapboxNavigation: mapboxNavigation,
voiceController: mapboxNavigationProvider.routeVoiceController,
eventsManager: mapboxNavigationProvider.eventsManager(),
topBanner: topBanner
)
let navigationViewController = NavigationViewController(
navigationRoutes: navigationRoutes,
navigationOptions: navigationOptions
)