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 navigation — startNavigationWithCurrentItinerary or startNavigationFromUserLocation
  3. Follow instructions — Navigation UI shows current step, remaining distance, and next instruction
  4. Arrive or stop — onArrivedAtDestination 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)
onNavigationRecalculatedRoute was recalculated during navigation; provides updated Navigation (new 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');
},
onNavigationRecalculated: (Navigation navigation) {
print('Recalculated: ${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