Skip to main content

Flutter Native - Navigation

This guide explains how to start, control, and integrate turn-by-turn navigation along an itinerary. Navigation follows a route computed and displayed via Itinerary. You must add an itinerary first, or use startNavigationFromUserLocation to compute and navigate in one step.


Overview

Navigation provides turn-by-turn guidance along an itinerary. The flow is:

  1. Add an itinerary — See Itinerary for addItineraryFromUserLocation, addItineraryFromMapCenter, or addItinerary
  2. Start navigationstartNavigationWithCurrentItinerary or startNavigationFromUserLocation
  3. Follow instructions — Navigation UI shows current step, remaining distance, and next instruction
  4. Arrive or stoponArrivedAtDestination fires, or user stops via stopNavigation

Starting navigation

With existing itinerary

After an itinerary is added (Itinerary), start turn-by-turn navigation:

await mapManager.startNavigationWithCurrentItinerary();

Optional: customize the route color during navigation:

await mapManager.startNavigationWithCurrentItinerary(color: Colors.purple);

Direct from user location (no prior itinerary)

Compute an itinerary and start navigation in one call. Requires location (GPS) or camera (VPS) permission granted before calling—see GPS and VPS.

await mapManager.startNavigationFromUserLocation(
destination: poi.coordinate,
searchRules: ItinerarySearchRules.WHEELCHAIR,
);

Stopping navigation

await mapManager.stopNavigation();

Callbacks

Listen to navigation events via WemapMap:

CallbackWhen triggered
onNavigationStartedNavigation begins; provides Navigation (contains itinerary)
onNavigationStoppedUser stopped navigation
onNavigationFailedNavigation failed (e.g. positioning lost)
onArrivedAtDestinationUser reached the destination
onNavigationInfoChangedProgress update (current step, remaining distance/time)
WemapMap(
options: MapOptions(...),
onNavigationStarted: (Navigation navigation) {
print('Started: ${navigation.itinerary.distance}m');
},
onNavigationStopped: () {
print('Stopped');
},
onNavigationFailed: (String error) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(error)));
},
onArrivedAtDestination: () {
print('Arrived!');
// Show success UI, play sound, etc.
},
onNavigationInfoChanged: (NavigationInfo info) {
// Update your UI: info.remainingDistance, info.remainingTime, info.nextStep
},
)

FieldTypeDescription
itineraryItineraryThe route being followed

Called frequently during navigation via onNavigationInfoChanged:

FieldTypeDescription
previousStepStep?Last completed step
nextStepStep?Current/upcoming step
legLegCurrent leg
traveledDistancedoubleDistance traveled so far (meters)
remainingDistancedoubleDistance to destination (meters)
remainingTimedoubleTime to destination (seconds)
remainingStepDistancedouble?Distance to next instruction point

Built-in widgets

Enable these in WemapMap to show the default navigation UI:

OptionDescription
navigationWidgetEnabled: trueShows NavigationWidget during turn-by-turn — current instruction, remaining distance/time, stop button
arrivedToDestinationDialog: trueShows a dialog when the user reaches the destination
navigationSuggestionDialog: trueShows a dialog ~10 seconds after an itinerary is added, suggesting to start navigation

See Widgets for screenshots.


Integration flow: POI → Itinerary → Navigation

When detailedViewEnabled, itineraryWidgetEnabled, and navigationWidgetEnabled are enabled:

  1. User taps a POI on the map → DetailedView opens
  2. User taps "Go there" → addItineraryFromUserLocation is called (Itinerary)
  3. Itinerary is computed and drawn → onItineraryAdded fires
  4. ItineraryWidget appears with duration and "Start" button
  5. User taps "Start" → startNavigationWithCurrentItinerary is called
  6. NavigationWidget shows turn-by-turn instructions
  7. On arrival → onArrivedAtDestination fires (and optionally arrivedToDestinationDialog)

Custom integration (no built-in NavigationWidget)

You can drive navigation entirely from your own UI:

// Start navigation
await mapManager.startNavigationWithCurrentItinerary();

// Listen for progress
onNavigationInfoChanged: (NavigationInfo info) {
setState(() {
_remainingMeters = info.remainingDistance.round();
_remainingSeconds = info.remainingTime.round();
_currentInstruction = info.nextStep?.navInstructions.instructions;
});
},

// Stop
ElevatedButton(
onPressed: () => mapManager.stopNavigation(),
child: Text('Stop'),
)

Troubleshooting

IssueSolution
startNavigationWithCurrentItinerary does nothingAdd an itinerary first (Itinerary); ensure onItineraryAdded fired
startNavigationFromUserLocation failsGrant location (GPS) or camera (VPS) permission before calling—see GPS and VPS
Navigation stops unexpectedlyCheck onNavigationFailed for error; may be due to positioning loss or connectivity
Instructions not announcedEnsure navigationWidgetEnabled or your custom UI handles onNavigationInfoChanged