nb_maps_flutter 3.1.0 copy "nb_maps_flutter: ^3.1.0" to clipboard
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.

example/lib/main.dart

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()));
}
5
likes
145
points
724
downloads

Publisher

verified publishernextbillion.ai

Weekly Downloads

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.

Repository (GitHub)
View/report issues

Documentation

API reference

License

BSD-3-Clause (license)

Dependencies

collection, flutter

More

Packages that depend on nb_maps_flutter

Packages that implement nb_maps_flutter