Map styles¶
Setup¶
Prerequisites¶
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.
Replace example_pathname
with the actual example path name,
such as address_search
Download project dependencies:
flutter upgrade
run the following terminal commands in the project directory,
where the pubspec.yaml
file is located:
flutter clean
flutter pub get
Run the example:
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,
without the line numbers, those are for reference:
1allprojects {
2 repositories {
3 google()
4 mavenCentral()
5 maven {
6 url "${rootDir}/../plugins/gem_kit/android/build"
7 }
8 }
9}
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 example pathname, such as center_coordinates
1android {
2 defaultConfig {
3 applicationId "com.magiclane.gem_kit.examples.example_pathname"
4 minSdk 21
5 targetSdk flutter.targetSdk
6 versionCode flutterVersionCode.toInteger()
7 versionName flutterVersionName
8 }
9 buildTypes {
10 release {
11 minifyEnabled false
12 shrinkResources false
13
14 // TODO: Add your own signing config for the release build.
15 // Signing with the debug keys for now, so `flutter run --release` works.
16 signingConfig signingConfigs.debug
17 }
18 }
19}
Then run the project:
flutter run --debug
flutter run --release
In the ios/Podfile
configuration text file, at the top, set the minimum ios
platform to 13 like this:
platform :ios, '13.0'
Then run the project:
flutter run --debug
flutter run --release
How it works¶
This example demonstrates how to use the gem_kit package to interact with a map and dynamically change its styles.
Import necessary packages¶
First, import the required packages in your Dart code.
1import 'package:gem_kit/content_store.dart';
2import 'package:gem_kit/core.dart';
3import 'package:gem_kit/map.dart';
4import 'package:flutter/material.dart';
5import 'dart:async';
Initialize GemKit¶
In the main function, initialize GemKit with your project API token.
1Future<void> main() async {
2 const projectApiToken = String.fromEnvironment('GEM_TOKEN');
3 await GemKit.initialize(appAuthorization: projectApiToken);
4 runApp(const MyApp());
5}
Build the main application¶
Define the main application widget, MyApp.
1class MyApp extends StatelessWidget {
2 const MyApp({super.key});
3
4 @override
5 Widget build(BuildContext context) {
6 return const MaterialApp(
7 debugShowCheckedModeBanner: false,
8 title: 'Map Styles',
9 home: MyHomePage(),
10 );
11 }
12}
Handle map styles in the stateful widget¶
Create the stateful widget, MyHomePage, which will handle map styles.
1class MyHomePage extends StatefulWidget {
2 const MyHomePage({super.key});
3
4 @override
5 State<MyHomePage> createState() => _MyHomePageState();
6}
Define state variables and methods¶
Within _MyHomePageState, define the necessary state variables and methods to interact with the map and manage styles.
1class _MyHomePageState extends State<MyHomePage> {
2 late GemMapController _mapController;
3 final _stylesList = <ContentStoreItem>[];
4 int _indexOfCurrentStyle = 0;
5 bool _isDownloadingStyle = false;
6
7 @override
8 void dispose() {
9 GemKit.release();
10 super.dispose();
11 }
12
13 @override
14 Widget build(BuildContext context) {
15 return Scaffold(
16 appBar: AppBar(
17 backgroundColor: Colors.deepPurple[900],
18 title: const Text(
19 'Map Styles',
20 style: TextStyle(color: Colors.white),
21 ),
22 actions: [
23 if (_isDownloadingStyle)
24 const SizedBox(
25 width: 20,
26 height: 20,
27 child: Center(
28 child: CircularProgressIndicator(
29 color: Colors.white,
30 ),
31 ),
32 ),
33 IconButton(
34 onPressed: () => _onMapButtonTap(context),
35 icon: const Icon(Icons.map_outlined, color: Colors.white))
36 ],
37 ),
38 body: GemMap(onMapCreated: _onMapCreated),
39 );
40 }
41
42 void _onMapCreated(GemMapController controller) async {
43 _mapController = controller;
44 SdkSettings.setAllowOffboardServiceOnExtraChargedNetwork(
45 ServiceGroupType.contentService, true);
46 getStyles();
47 }
48
49 void getStyles() {
50 ContentStore.asyncGetStoreContentList(ContentType.viewStyleLowRes,
51 (err, items, isCached) {
52 if (err == GemError.success && items != null) {
53 _stylesList.addAll(items);
54 ScaffoldMessenger.of(context).clearSnackBars();
55 }
56 });
57 }
58
59 Future<bool> _downloadStyle(ContentStoreItem style) async {
60 setState(() {
61 _isDownloadingStyle = true;
62 });
63 Completer<bool> completer = Completer<bool>();
64 style.asyncDownload((err) {
65 if (err != GemError.success) {
66 completer.complete(false);
67 setState(() {
68 _isDownloadingStyle = false;
69 });
70 return;
71 }
72 completer.complete(true);
73 setState(() {
74 _isDownloadingStyle = false;
75 });
76 }, onProgressCallback: (progress) {
77 print('progress: $progress');
78 }, allowChargedNetworks: true);
79 return await completer.future;
80 }
81
82 void _showSnackBar(BuildContext context,
83 {required String message, Duration duration = const Duration(hours: 1)}) {
84 final snackBar = SnackBar(
85 content: Text(message),
86 duration: duration,
87 );
88 ScaffoldMessenger.of(context).showSnackBar(snackBar);
89 }
90
91 Future<void> _onMapButtonTap(BuildContext context) async {
92 if (_stylesList.isEmpty) {
93 _showSnackBar(context, message: "The map styles are loading.");
94 getStyles();
95 return;
96 }
97
98 final indexOfNextStyle = (_indexOfCurrentStyle >= _stylesList.length - 1)
99 ? 0
100 : _indexOfCurrentStyle + 1;
101 ContentStoreItem currentStyle = _stylesList[indexOfNextStyle];
102
103 if (!currentStyle.isCompleted) {
104 final didDownloadSuccessfully = await _downloadStyle(currentStyle);
105 if (!didDownloadSuccessfully) return;
106 }
107
108 _indexOfCurrentStyle = indexOfNextStyle;
109 final String filename = currentStyle.fileName;
110 _mapController.preferences.setMapStyleByPath(filename);
111 setState(() {});
112 }
113}
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¶
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.