Full Navigation Experience Example
Introduction
- This example shows:
- Display a MapView
- Track Current Location
- onMapClick
- onMapLongClick
- onUserLocationUpdate
- Customize marker image of route origin and destination
- Fetch route with RouteRequestParams
- NBNavigation.fetchRoute(requestParams, (routes, error) async
- Draw routes with route result
- navNextBillionMap.drawRoute(routes);
- Start Navigation with LauncherConfig
- NBNavigation.startNavigation(config)
![]() | ![]() |
Android snapshot | iOS snapshot |
For all code examples, refer to Flutter Navigation Code Example
FullNavigationExample view source
1import 'dart:math';
2
3import 'package:flutter/material.dart';
4import 'package:flutter/services.dart';
5import 'package:fluttertoast/fluttertoast.dart';
6import 'package:nb_navigation_flutter/nb_navigation_flutter.dart';
7import 'package:nb_maps_flutter/nb_maps_flutter.dart';
8
9class FullNavigationExample extends StatefulWidget {
10 static const String title = "Full Navigation Experience Example";
11
12
13 FullNavigationExampleState createState() => FullNavigationExampleState();
14}
15
16class FullNavigationExampleState extends State<FullNavigationExample> {
17 NextbillionMapController? controller;
18 List<DirectionsRoute> routes = [];
19 late NavNextBillionMap navNextBillionMap;
20 Symbol? mapMarkerSymbol;
21
22 String locationTrackImage = "assets/location_on.png";
23 UserLocation? currentLocation;
24 List<LatLng> waypoints = [];
25
26 void _onMapCreated(NextbillionMapController controller) {
27 this.controller = controller;
28 }
29
30 _onStyleLoadedCallback() async {
31 if (controller != null) {
32 navNextBillionMap = NavNextBillionMap(controller!);
33 loadAssetImage();
34 }
35 Fluttertoast.showToast(msg: "Long click to select destination and fetch a route");
36 Future.delayed(const Duration(milliseconds: 80), () {
37 controller?.updateMyLocationTrackingMode(MyLocationTrackingMode.Tracking);
38 });
39 }
40
41 _onMapLongClick(Point<double> point, LatLng coordinates) {
42 _fetchRoute(coordinates);
43 }
44
45
46 _onMapClick(Point<double> point, LatLng coordinates) {
47 navNextBillionMap.addRouteSelectedListener(coordinates, (selectedRouteIndex) {
48 if (routes.isNotEmpty && selectedRouteIndex != 0) {
49 var selectedRoute = routes[selectedRouteIndex];
50 routes.removeAt(selectedRouteIndex);
51 routes.insert(0, selectedRoute);
52 setState(() {
53 routes = routes;
54 });
55 navNextBillionMap.drawRoute(routes);
56 }
57 });
58 }
59
60 _onUserLocationUpdate(UserLocation location) {
61 currentLocation = location;
62 }
63
64 _onCameraTrackingChanged() {
65 setState(() {
66 locationTrackImage = 'assets/location_off.png';
67 });
68 }
69
70
71 Widget build(BuildContext context) {
72 return Stack(
73 children: [
74 NBMap(
75 onMapCreated: _onMapCreated,
76 onStyleLoadedCallback: _onStyleLoadedCallback,
77 initialCameraPosition: const CameraPosition(
78 target: LatLng(0, 0),
79 zoom: 14.0,
80 ),
81 trackCameraPosition: true,
82 myLocationEnabled: true,
83 myLocationTrackingMode: MyLocationTrackingMode.Tracking,
84 onMapLongClick: _onMapLongClick,
85 onUserLocationUpdated: _onUserLocationUpdate,
86 onCameraTrackingDismissed: _onCameraTrackingChanged,
87 onMapClick: _onMapClick,
88 ),
89 Padding(
90 padding: const EdgeInsets.all(8.0),
91 child: Column(
92 mainAxisAlignment: MainAxisAlignment.end,
93 crossAxisAlignment: CrossAxisAlignment.start,
94 children: [
95 Padding(
96 padding: const EdgeInsets.all(8.0),
97 child: GestureDetector(
98 child: Image(
99 image: AssetImage(locationTrackImage),
100 width: 28,
101 height: 28,
102 ),
103 onTap: () {
104 controller?.updateMyLocationTrackingMode(MyLocationTrackingMode.Tracking);
105 setState(() {
106 locationTrackImage = 'assets/location_on.png';
107 });
108 }),
109 ),
110 const Padding(padding: EdgeInsets.only(top: 35)),
111 Row(
112 mainAxisAlignment: MainAxisAlignment.center,
113 children: [
114 ElevatedButton(
115 style: ButtonStyle(
116 backgroundColor: MaterialStateProperty.all(routes.isEmpty ? Colors.grey : Colors.blueAccent),
117 enableFeedback: routes.isNotEmpty),
118 onPressed: () {
119 clearRouteResult();
120 waypoints.clear();
121 },
122 child: const Text("Clear Routes")),
123 const Padding(padding: EdgeInsets.only(left: 8)),
124 ElevatedButton(
125 style: ButtonStyle(
126 backgroundColor: MaterialStateProperty.all(routes.isEmpty ? Colors.grey : Colors.blueAccent),
127 enableFeedback: routes.isNotEmpty),
128 onPressed: () {
129 _startNavigation();
130 },
131 child: const Text("Start Navigation")),
132 ],
133 ),
134 const Padding(padding: EdgeInsets.only(top: 48)),
135 // Padding(
136 // padding: const EdgeInsets.only(top: 8.0),
137 // child: Text("route response: ${routeResult}"),
138 // ),
139 ],
140 ),
141 )
142 ],
143 );
144 }
145
146
147 void _fetchRoute(LatLng destination) async {
148 if (currentLocation == null) {
149 return;
150 }
151 LatLng origin = currentLocation!.position;
152 waypoints.add(destination);
153 RouteRequestParams requestParams = RouteRequestParams(
154 origin: origin,
155 destination: waypoints.last,
156 // overview: ValidOverview.simplified,
157 // avoid: [SupportedAvoid.toll, SupportedAvoid.ferry],
158 // option: SupportedOption.flexible,
159 // truckSize: [200, 200, 600],
160 // truckWeight: 100,
161 // unit: SupportedUnits.imperial,
162 alternatives: true,
163 mode: ValidModes.car,
164 geometryType: SupportedGeometry.polyline,
165 );
166
167 if (waypoints.length > 1) {
168 requestParams.waypoints = waypoints.sublist(0, waypoints.length - 1);
169 }
170
171 await NBNavigation.fetchRoute(requestParams, (routes, error) async {
172 if (routes.isNotEmpty) {
173 clearRouteResult();
174 setState(() {
175 this.routes = routes;
176 });
177 await drawRoutes(routes);
178 addImageFromAsset(destination);
179 } else if (error != null) {
180 print("====error====${error}");
181 }
182 });
183 }
184
185 Future<void> drawRoutes(List<DirectionsRoute> routes) async {
186 // navNextBillionMap.toggleDurationSymbolVisibilityWith(false);
187 await navNextBillionMap.drawRoute(routes);
188 }
189
190 void clearRouteResult() {
191 navNextBillionMap.clearRoute();
192 controller?.clearSymbols();
193 setState(() {
194 routes.clear();
195 });
196 }
197
198 void _startNavigation() {
199 if (routes.isEmpty) return;
200 NavigationLauncherConfig config = NavigationLauncherConfig(route: routes.first, routes: routes);
201 config.locationLayerRenderMode = LocationLayerRenderMode.GPS;
202 config.enableDissolvedRouteLine = false;
203 config.shouldSimulateRoute = false;
204 config.themeMode = NavigationThemeMode.system;
205 config.useCustomNavigationStyle = false;
206 NBNavigation.startNavigation(config);
207 }
208
209 Future<void> loadAssetImage() async {
210 final ByteData bytes = await rootBundle.load("assets/map_marker_light.png");
211 final Uint8List list = bytes.buffer.asUint8List();
212 await controller?.addImage("ic_marker_destination", list);
213 }
214
215 Future<void> addImageFromAsset(LatLng coordinates) async {
216 controller?.clearSymbols();
217 var symbolOptions = SymbolOptions(
218 geometry: coordinates,
219 iconImage: "ic_marker_destination",
220 );
221 await controller?.addSymbol(symbolOptions);
222 controller?.symbolManager?.setTextAllowOverlap(false);
223 }
224
225
226 void initState() {
227 super.initState();
228 }
229
230
231 void dispose() {
232 // TODO: implement dispose
233 super.dispose();
234 }
235
236
237 void didUpdateWidget(FullNavigationExample oldWidget) {
238 // TODO: implement didUpdateWidget
239 super.didUpdateWidget(oldWidget);
240 }
241
242
243 void didChangeDependencies() {
244 // TODO: implement didChangeDependencies
245 super.didChangeDependencies();
246 }
247}
Code summary
The above code snippet demonstrates a full navigation experience using the "nb_navigation_flutter" and "nb_maps_flutter" packages. It provides functionalities to display a map with a user's current location, select a destination by long-pressing on the map, fetch a route from the user's current location to the selected destination, and start navigation with turn-by-turn directions.
How to display NBMap Widget:
- The NBMap widget is displayed using the **"NBMap" **class from the "nb_maps_flutter" package. It is placed in the stack of widgets and is provided with various properties like onMapCreated, initialCameraPosition, myLocationEnabled, etc., to configure its behavior.
Customize marker image of route origin and destination:
The marker image for the route origin and destination is customized using the method loadAssetImage. It loads a custom marker image from the assets folder and adds it to the map using the "addImage" method of the "NextbillionMapController".
Fetch route with RouteRequestParams: The route is fetched using the _fetchRoute method. It takes the destination coordinates, constructs a RouteRequestParams object with various route parameters like origin, destination, unit, mode, and geometryType, and then calls the NBNavigation.fetchRoute method to retrieve the route information.
Draw routes with route result: The drawn routes are displayed on the map using the drawRoutes method. It takes a list of DirectionsRoute objects and calls navNextBillionMap.drawRoute to render the route on the map.
Start Navigation with LauncherConfig: The navigation is started using the _startNavigation method. It constructs a NavigationLauncherConfig object with various configuration options like route, locationLayerRenderMode, enableDissolvedRouteLine, shouldSimulateRoute, etc., and then calls NBNavigation.startNavigation to begin the navigation.
The code also includes various event handlers like _onMapCreated, _onStyleLoadedCallback, _onMapLongClick, _onMapClick, _onUserLocationUpdate, and _onCameraTrackingChanged, which handle map interactions, user location updates, and camera tracking changes.