Skip to main content
GuidesAPI ReferenceExamplesFAQ

Lane Instruction

Estimated reading time: 3 minutes

This example demonstrates how to build a Flutter app that calculates routes and displays lane instructions using the Maps SDK for Flutter.

How it works

The example app demonstrates the following features:

  • Initializes GemKit and calculates a route between landmarks.
  • Allows users to simulate navigation along the calculated route.
  • Displays lane instructions with real-time lane guidance.
hello_map
Lane instruction image displayed

UI and Map Integration

The following code demonstrates how to build a user interface featuring a GemMap widget and an app bar with a route and navigation button.

const projectApiToken = String.fromEnvironment('GEM_TOKEN');

void main() {
runApp(const MyApp());
}

class MyApp extends StatelessWidget {
const MyApp({super.key});


Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Lane Instructions',
home: MyHomePage(),
);
}
}

class MyHomePage extends StatefulWidget {
const MyHomePage({super.key});


State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
late GemMapController _mapController;
late NavigationInstruction currentInstruction;

bool _areRoutesBuilt = false;
bool _isSimulationActive = false;

// We use the progress listener to cancel the route calculation.
TaskHandler? _routingHandler;

// We use the progress listener to cancel the navigation.
TaskHandler? _navigationHandler;


void dispose() {
GemKit.release();
super.dispose();
}


Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text(
"Lane Instructions",
style: TextStyle(color: Colors.white),
),
backgroundColor: Colors.deepPurple[900],
actions: [
if (!_isSimulationActive && _areRoutesBuilt)
IconButton(
onPressed: _startSimulation,
icon: const Icon(Icons.play_arrow, color: Colors.white),
),
if (_isSimulationActive)
IconButton(
onPressed: _stopSimulation,
icon: const Icon(Icons.stop, color: Colors.white),
),
if (!_areRoutesBuilt)
IconButton(
onPressed: () => _onBuildRouteButtonPressed(context),
icon: const Icon(Icons.route, color: Colors.white),
),
],
),
body: Stack(
children: [
GemMap(
key: ValueKey("GemMap"),
onMapCreated: _onMapCreated,
appAuthorization: projectApiToken,
),
if (_isSimulationActive)
Align(
alignment: Alignment.bottomCenter,
child: Padding(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).padding.bottom + 40,
),
child: Padding(
padding: const EdgeInsets.all(8.0),
// Call getLaneImage on instruction
child:
currentInstruction.laneImg.isValid
? Image.memory(
currentInstruction.laneImg
.getRenderableImage(
size: Size(100, 50),
format: ImageFileFormat.png,
allowResize: true,
)!
.bytes,
gaplessPlayback: true,
)
: SizedBox(),
),
),
),
],
),
resizeToAvoidBottomInset: false,
);
}

void _onMapCreated(GemMapController controller) {
_mapController = controller;
}
}

Route Calculation and Simulation

The calculateRoute method calculates a route between two landmarks and displays it on the map.

void _onBuildRouteButtonPressed(BuildContext context) {
final departureLandmark = Landmark.withLatLng(latitude: 45.649572, longitude: 25.628333);
final destinationLandmark = Landmark.withLatLng(latitude: 44.4379187, longitude: 26.0122374);

final routePreferences = RoutePreferences();
_showSnackBar(context, message: 'The route is calculating.');

_routingHandler = RoutingService.calculateRoute(
[departureLandmark, destinationLandmark],
routePreferences,
(err, routes) async {
_routingHandler = null;

ScaffoldMessenger.of(context).clearSnackBars();

if (err == GemError.success) {
final routesMap = _mapController.preferences.routes;

for (final route in routes) {
routesMap.add(
route,
route == routes.first,
label: route.getMapLabel(),
);
}

_mapController.centerOnRoutes(routes: routes);
}
setState(() {
_areRoutesBuilt = true;
});
},
);
}

The startSimulation method triggers a simulated navigation session, updating the UI with lane instructions.

void _startSimulation() {

final routes = _mapController.preferences.routes;
_mapController.preferences.routes.clearAllButMainRoute();

if (routes.mainRoute == null) {
_showSnackBar(context, message: "No main route available");
return;
}

_navigationHandler = NavigationService.startSimulation(
routes.mainRoute!,
null,
onNavigationInstruction: (instruction, events) {
setState(() {
_isSimulationActive = true;
});
currentInstruction = instruction;
},
onError: (error) {
setState(() {
_isSimulationActive = false;
_cancelRoute();
});

if (error != GemError.cancel) {
_stopSimulation();
}
return;
},
);
_mapController.startFollowingPosition();
}

UI Components

Lane Instruction Display shows current lane instructions based on the navigation data.

Align(
alignment: Alignment.bottomCenter,
child: Padding(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).padding.bottom + 40,
),
child: Padding(
padding: const EdgeInsets.all(8.0),
// Call laneImg on instruction
child: currentInstruction.laneImg.isValid
? Image.memory(
currentInstruction.laneImg
.getRenderableImage(size: Size(100, 50), format: ImageFileFormat.png, allowResize: true)!
.bytes,
gaplessPlayback: true,
)
: SizedBox(),
),
),
),

Flutter Examples

Maps SDK for Flutter Examples can be downloaded or cloned with Git.