nb_maps_flutter 3.1.0
nb_maps_flutter: ^3.1.0 copied to clipboard
A Flutter plugin for Nextbillion.ai Maps SDK that provides cross-platform map functionality with custom styles, camera controls, location tracking, and various annotation types.
import 'dart:io';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:nb_maps_flutter/nb_maps_flutter.dart';
import 'package:nb_maps_flutter_example/map_ui.dart';
import 'package:nb_maps_flutter_example/scrolling_map.dart';
import 'package:nb_maps_flutter_example/sources.dart';
import 'package:nb_maps_flutter_example/take_snapshot.dart';
import 'package:nb_maps_flutter_example/track_current_location.dart';
import 'package:permission_handler/permission_handler.dart';
import 'add_image_test.dart';
import 'animate_camera.dart';
import 'annotation_order_maps.dart';
import 'click_annotations.dart';
import 'custom_marker.dart';
import 'encoded_geometry_example.dart';
import 'layer.dart';
import 'line.dart';
import 'local_style.dart';
import 'map_style_switch.dart';
import 'move_camera.dart';
import 'offline_regions.dart';
import 'page.dart';
import 'place_batch.dart';
import 'place_circle.dart';
import 'place_fill.dart';
import 'place_source.dart';
import 'place_symbol.dart';
final List<ExamplePage> _allPages = <ExamplePage>[
const MapUiPage(),
MapStyleSwitchPage(),
const AnimateCameraPage(),
const MoveCameraPage(),
const PlaceSymbolPage(),
const PlaceSourcePage(),
const LinePage(),
const LocalStylePage(),
const LayerPage(),
const PlaceCirclePage(),
const PlaceFillPage(),
const ScrollingMapPage(),
const OfflineRegionsPage(),
const AnnotationOrderPage(),
const CustomMarkerPage(),
const BatchAddPage(),
const TakeSnapPage(),
const ClickAnnotationPage(),
const Sources(),
const TrackCurrentLocationPage(),
const EncodedGeometryPage(),
AddImageTestPage()
];
class MapsDemo extends StatefulWidget {
static const String accessKey = String.fromEnvironment("ACCESS_KEY");
@override
State<MapsDemo> createState() => _MapsDemoState();
}
class _MapsDemoState extends State<MapsDemo> {
// By default , the maps SDK is using the 'WellKnownTileServer.nbTomtom' tile server
WellKnownTileServer currentTileServer = WellKnownTileServer.nbTomtom;
bool isSwitchingTileServer = false;
@override
void initState() {
super.initState();
NextBillion.initNextBillion(MapsDemo.accessKey);
NextBillion.getUserId().then((value) {
if (kDebugMode) {
print("User id: $value");
}
});
NextBillion.setUserId("1234");
NextBillion.getNbId().then((value) {
if (kDebugMode) {
print("NB id: $value");
}
});
NextBillion.getUserId().then((value) {
if (kDebugMode) {
print("User id: $value");
}
});
}
/// Determine the android version of the phone and turn off HybridComposition
/// on older sdk versions to improve performance for these
///
/// !!! Hybrid composition is currently broken do no use !!!
Future<void> initHybridComposition() async {
if (!kIsWeb && Platform.isAndroid) {
final androidInfo = await DeviceInfoPlugin().androidInfo;
final sdkVersion = androidInfo.version.sdkInt;
if (sdkVersion >= 29) {
NBMap.useHybridComposition = true;
} else {
NBMap.useHybridComposition = false;
}
}
}
Future<void> _pushPage(BuildContext context, ExamplePage page) async {
final status = await Permission.location.status;
if (status.isDenied) {
await [Permission.location].request();
}
if (!mounted) return; // Check if the widget is still mounted
// ignore: use_build_context_synchronously
Navigator.of(context).push(MaterialPageRoute<void>(
builder: (_) => Scaffold(
appBar: AppBar(title: Text(page.title)),
body: page,
),
));
}
Future<void> _switchTileServer() async {
if (isSwitchingTileServer) return;
setState(() {
isSwitchingTileServer = true;
});
try {
// Switch to the other tile server
final newTileServer = currentTileServer == WellKnownTileServer.nbTomtom
? WellKnownTileServer.nbMapTiler
: WellKnownTileServer.nbTomtom;
final success = await NextBillion.switchWellKnownTileServer(newTileServer) ?? false;
if (success) {
setState(() {
currentTileServer = newTileServer;
});
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('Switched to ${_getTileServerName(newTileServer)}'),
backgroundColor: Colors.green,
duration: const Duration(seconds: 2),
));
} else {
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
content: Text('Failed to switch tile server'),
backgroundColor: Colors.red,
duration: Duration(seconds: 2),
));
}
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('Error switching tile server: $e'),
backgroundColor: Colors.red,
duration: const Duration(seconds: 2),
));
} finally {
setState(() {
isSwitchingTileServer = false;
});
}
}
String _getTileServerName(WellKnownTileServer server) {
switch (server) {
case WellKnownTileServer.nbTomtom:
return 'TomTom';
case WellKnownTileServer.nbMapTiler:
return 'MapTiler';
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('NbMaps examples'),
actions: [
// Tile Server Switch Button
Padding(
padding: const EdgeInsets.all(8.0),
child: ElevatedButton.icon(
onPressed: isSwitchingTileServer ? null : _switchTileServer,
icon: isSwitchingTileServer
? const SizedBox(
width: 16,
height: 16,
child: CircularProgressIndicator(strokeWidth: 2),
)
: const Icon(Icons.swap_horiz, size: 16),
label: Text(
isSwitchingTileServer
? 'Switching...'
: _getTileServerName(currentTileServer),
style: const TextStyle(fontSize: 12),
),
style: ElevatedButton.styleFrom(
backgroundColor: Theme.of(context).primaryColor,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
),
),
),
],
),
body: MapsDemo.accessKey.isEmpty ||
MapsDemo.accessKey.contains("YOUR_TOKEN")
? buildAccessTokenWarning()
: Column(
children: [
// Current Tile Server Info
Container(
width: double.infinity,
padding: const EdgeInsets.all(16),
color: Colors.grey[100],
child: Row(
children: [
const Icon(Icons.info_outline, size: 16),
const SizedBox(width: 8),
Text(
'Current Tile Server: ${_getTileServerName(currentTileServer)}',
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 14,
),
),
],
),
),
// Examples List
Expanded(
child: ListView.separated(
itemCount: _allPages.length,
separatorBuilder: (BuildContext context, int index) =>
const Divider(height: 1),
itemBuilder: (_, int index) => ListTile(
leading: _allPages[index].leading,
title: Text(_allPages[index].title),
onTap: () => _pushPage(context, _allPages[index]),
),
),
),
],
),
);
}
Widget buildAccessTokenWarning() {
return Container(
color: Colors.red[900],
child: SizedBox.expand(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
"Using MapView requires calling Nextbillion.initNextbillion(String accessKey) before inflating or creating NBMap Widget."
]
.map((text) => Padding(
padding: const EdgeInsets.all(8),
child: Text(
text,
textAlign: TextAlign.center,
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
))
.toList(),
),
),
);
}
}
void main() {
runApp(MaterialApp(home: MapsDemo()));
}