Skip to content

Map Styles

This example explains how to download and apply different map styles, including styles for day and night, some of which feature topography.

map_styles - example flutter screenshot

Setup

First, get an API key token, see the Getting Started guide.

Prerequisites

Make sure you completed the Environment Setup - Flutter Examples guide before starting this guide.

Build and run

Go to the map_styles directory within the Flutter examples directory. This is the name of the example project.

Note - the gem_kit directory containing the Maps SDK for Flutter should be in the plugins directory of the example, e.g. example_pathname/plugins/gem_kit - see the environment setup guide above.

Run: flutter pub get

Configure the native parts:

First, verify that the ANDROID_SDK_ROOT environment variable is set to the root path of your android SDK.

In android/build.gradle add the maven block as shown, within the allprojects block, for both debug and release builds:

allprojects {
    repositories {
        google()
        mavenCentral()
        maven {
           url "${rootDir}/../plugins/gem_kit/android/build"
        }
    }
}

in android/app/build.gradle within the android block, in the defaultConfig block, the android SDK version minSdk must be set as shown below.

Additionally, for release builds, in android/app/build.gradle, within the android block, add the buildTypes block as shown:

Replace example_pathname with the actual project pathname

android {
    defaultConfig {
        applicationId "com.magiclane.gem_kit.examples.example_pathname"
        minSdk 21
        targetSdk flutter.targetSdk
        versionCode flutterVersionCode.toInteger()
        versionName flutterVersionName
    }
    buildTypes {
        release {
            minifyEnabled false
            shrinkResources false

            // TODO: Add your own signing config for the release build.
            // Signing with the debug keys for now, so `flutter run --release` works.
            signingConfig signingConfigs.debug
        }
    }
}

In the ios/Podfile configuration file, at the top, set the minimum ios platform version to 14 like this:

platform :ios, '14.0'

We recommend you to run these commands after you copy the gem_kit into your project: |flutter clean |flutter pub get |and |cd ios |pod install

Then run the project:

flutter run --debug
or
flutter run --release

App entry and initialization

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

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

This code initializes the projectApiToken with the required authorization token and launches the app.

How it works

This example demonstrates the following features:

  • Display and manage various map styles dynamically.

  • Provide smooth transitions between styles while ensuring a seamless user experience.

map_styles - example flutter screenshot

Build the main application

Define the main application widget, MyApp.

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

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Map Styles',
      home: MyHomePage(),
    );
  }
}

Handle map styles in the stateful widget

Create the stateful widget, MyHomePage, which will handle map styles.

map_styles - example flutter screenshot

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

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

Define state variables and methods

Within _MyHomePageState, define the necessary state variables and methods to interact with the map and manage styles.

class _MyHomePageState extends State<MyHomePage> {
  late GemMapController _mapController;
  final _stylesList = <ContentStoreItem>[];
  int _indexOfCurrentStyle = 0;
  bool _isDownloadingStyle = false;

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.deepPurple[900],
        title: const Text(
          'Map Styles',
          style: TextStyle(color: Colors.white),
        ),
        actions: [
          if (_isDownloadingStyle)
            const SizedBox(
              width: 20,
              height: 20,
              child: Center(
                child: CircularProgressIndicator(
                  color: Colors.white,
                ),
              ),
            ),
          IconButton(
              onPressed: () => _onMapButtonTap(context),
              icon: const Icon(Icons.map_outlined, color: Colors.white))
        ],
      ),
      body: GemMap(onMapCreated: _onMapCreated,),
    );
  }

  void _onMapCreated(GemMapController controller) async {
    _mapController = controller;
    SdkSettings.setAllowOffboardServiceOnExtraChargedNetwork(
        ServiceGroupType.contentService, true);
    getStyles();
  }

  void getStyles() {
    ContentStore.asyncGetStoreContentList(ContentType.viewStyleLowRes,
        (err, items, isCached) {
      if (err == GemError.success && items != null) {
        _stylesList.addAll(items);
        ScaffoldMessenger.of(context).clearSnackBars();
      }
    });
  }

  Future<bool> _downloadStyle(ContentStoreItem style) async {
    setState(() {
      _isDownloadingStyle = true;
    });
    Completer<bool> completer = Completer<bool>();
    style.asyncDownload((err) {
      if (err != GemError.success) {
        completer.complete(false);
        setState(() {
          _isDownloadingStyle = false;
        });
        return;
      }
      completer.complete(true);
      setState(() {
        _isDownloadingStyle = false;
      });
    }, onProgressCallback: (progress) {
      print('progress: $progress');
    }, allowChargedNetworks: true);
    return await completer.future;
  }

  void _showSnackBar(BuildContext context,
      {required String message, Duration duration = const Duration(hours: 1)}) {
    final snackBar = SnackBar(
      content: Text(message),
      duration: duration,
    );
    ScaffoldMessenger.of(context).showSnackBar(snackBar);
  }

  Future<void> _onMapButtonTap(BuildContext context) async {
    if (_stylesList.isEmpty) {
      _showSnackBar(context, message: "The map styles are loading.");
      getStyles();
      return;
    }

    final indexOfNextStyle = (_indexOfCurrentStyle >= _stylesList.length - 1)
        ? 0
        : _indexOfCurrentStyle + 1;
    ContentStoreItem currentStyle = _stylesList[indexOfNextStyle];

    if (!currentStyle.isCompleted) {
      final didDownloadSuccessfully = await _downloadStyle(currentStyle);
      if (!didDownloadSuccessfully) return;
    }

    _indexOfCurrentStyle = indexOfNextStyle;
    final String filename = currentStyle.fileName;
    _mapController.preferences.setMapStyleByPath(filename);
    setState(() {});
  }
}

Explanation of the key components

  • GemMapController: This is used to interact with the map.

  • ContentStoreItem: Represents a downloadable map style.

  • getStyles: Loads available map styles.

  • _downloadStyle: Downloads a selected style.

  • _onMapButtonTap: Changes the current map style.

map_styles - example flutter screenshot

Map Styles

The example supports various map styles, including: - Day and Night Styles: Provides different visual representations for day and night. - Topography Styles: Adds terrain relief to the map.

night style - example flutter screenshot

night style - example flutter screenshot

relief style - example flutter screenshot

night style - example flutter screenshot

relief style - example flutter screenshot

night style - example flutter screenshot

Flutter Examples

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