Skip to main content

Styling

Last updated: October 9, 2026 | 8 minutes read

Learn how to customize map appearance using predefined styles or custom styles created in Magic Lane Map Studio.

Apply predefined styles​

Predefined map styles must be downloaded before use, as they are not loaded into memory by default. Use the ContentStore class to retrieve and download available styles.

Get available styles​

Retrieve a list of all available map styles as a List<ContentStoreItem>:

void getStyles() {
ContentStore.asyncGetStoreContentList(ContentType.viewStyleLowRes,
(err, items, isCached) {
if (err == GemError.success && items.isNotEmpty) {
for (final item in items) {
_stylesList.add(item);
}
ScaffoldMessenger.of(context).clearSnackBars();
}
});
}

The asyncGetStoreContentList method can be used to obtain other content such as car models, road maps, TTS voices, and more.

info

Two types of preview styles are available:

  • ContentType.viewStyleHighRes - optimized for high-resolution displays (mobile devices)
  • ContentType.viewStyleLowRes - optimized for low-resolution displays (desktop monitors)

The onComplete parameter of the asyncGetStoreContentList method provides:

  • GemError - indicates whether any errors occurred during the operation
  • List<ContentStoreItem> - contains the retrieved items (empty if error is not GemError.success)
  • boolean - specifies whether the item is already cached or needs downloading

ContentStoreItem attributes​

A ContentStoreItem has the following attributes and methods:

Attribute/MethodsExplanation
nameGets the name of the associated product.
idGet the unique id of the item in the content store.
chapterNameGets the product chapter name translated to interface language.
countryCodesGets the country code (ISO 3166-1 alpha-3) list of the product as text.
languageGets the full language code for the product.
typeGets the type of the product as a [ContentType] value.
fileNameGets the full path to the content data file when available.
clientVersionGets the client version of the content.
totalSizeGet the size of the content in bytes.
availableSizeGets the available size of the content in bytes.
isCompletedChecks if the item is completed downloaded.
statusGets current item status.
pauseDownloadPause a previous download operation.
cancelDownloadCancel a previous download operation.
downloadProgressGet current download progress.
canDeleteContentCheck if associated content can be deleted.
deleteContentDelete the associated content
isImagePreviewAvailableCheck if there is an image preview available on the client.
imgPreviewGet the preview. The user is responsible to check if the image is valid.
contentParametersGet additional parameters for the content.
updateItemGet corresponding update item.
isUpdatableCheck if item is updatable, i.e. it has a newer version available.
updateSizeGet update size (if an update is available for this item).
updateVersionGet update version (if an update is available for this item).
asyncDownloadAsynchronous start/resume the download of the content store product content.
danger

Certain attributes may not apply to specific types of ContentStoreItem. For example, countryCodes will not provide meaningful data for ContentType.viewStyleLowRes, as styles are not associated with any country.

Download a style​

Download a map style by calling ContentStoreItem.asyncDownload():

style.asyncDownload(
(err) {
if (err != GemError.success) {
showSnackbar("Download failed with error $err");
} else {
showSnackbar("Download succeeded");
}
},
onProgress: (progress) {
print('Download progress: $progress');
},
allowChargedNetworks: true
);

You can control whether to allow downloads over metered networks by setting the allowChargedNetworks parameter. The onProgress callback provides the download progress as a percentage (0-100).

Apply the downloaded style​

Apply the downloaded style using GemMapController.MapViewPreferences.setMapStyleByPath(path) with the filename:

final String filename = currentStyle.fileName;
mapController.preferences.setMapStyleByPath(filename);

Alternative methods to set styles​

You can also set map styles using:

  • MapViewPreferences.setMapStyle() - takes a ContentStoreItem of type ContentType.viewStyleHighRes or ContentType.viewStyleLowRes
  • MapViewPreferences.setMapStyleById() - takes the unique id obtained from ContentStoreItem.id
mapController.preferences.setMapStyle(currentStyle);
mapController.preferences.setMapStyleById(currentStyle.id);

Apply custom styles​

Create a custom map style in Magic Lane Map Studio. The process generates a .style file that you can load into your application.

Add style file to assets​

Create an assets directory in the root of your project and place the .style file there. Add the following lines to your pubspec.yaml file under the flutter: section:

flutter:
uses-material-design: true

assets:
- assets/

This allows the flutter/services.dart package to access the assets directory.

Load style into memory​

Load the style into memory with the following code:

// Method to load style and return it as bytes
Future<Uint8List> _loadStyle() async {
// Load style into memory
final data = await rootBundle.load('assets/Basic_1_Oldtime-1_21_656.style');

// Convert it to Uint8List
final bytes = data.buffer.asUint8List();

return bytes;
}
danger

Import 'package:flutter/services.dart' for rootBundle.load() to work.

Apply the custom style​

Once the map style bytes are obtained, set the style using MapViewPreferences.setMapStyleByBuffer(styleData):

final styleData = await _loadStyle();

mapController.preferences
.setMapStyleByBuffer(styleData, smoothTransition: true);

Enable smooth transition by passing true to the smoothTransition parameter.

Default map style
Custom added map style

Set initial map style​

Apply a map style when creating a GemMap by providing a relative path to the .style file using the initialMapStyleAsset parameter:

GemMap(
appAuthorization: projectApiToken,
initialMapStyleAsset: "assets/map-styles/my_map_style.style",
),
info

When using initialMapStyleAsset, the path is relative to the project root and only works on Android and iOS.

Use a custom map font​

Use MapViewPreferences.setMapFont to draw the map labels with your own .ttf or .otf files instead of the built-in font and of the font defined by the map style. The paths are file system paths, so a font bundled as a Flutter asset must first be written to a file:

// The font must be a file on disk: write the bundled asset to a file first
final ByteData data =
await rootBundle.load('fonts/MaterialIcons-Regular.otf');
final Directory dir = await getApplicationDocumentsDirectory();
final File fontFile = File('${dir.path}/MaterialIcons-Regular.otf');
await fontFile.writeAsBytes(
data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes));

// Each path replaces one face; a face without a path keeps the built-in one
final GemError error = mapController.preferences.setMapFont(
fontFile.path,
boldPath: fontFile.path,
);
if (error != GemError.success) {
showSnackbar("Could not load the font: $error");
return;
}

showSnackbar("Map font: ${mapController.preferences.mapFontPath}");

// Pass an empty path to restore the style / built-in font
// mapController.preferences.setMapFont('');

Each path replaces one face (regular, bold, italic). A face without a path keeps the built-in one, and characters missing from a custom face are drawn with the built-in font. All the given files are read before anything changes, so on error the current font is kept. The method returns GemError.notFound when a file is missing or empty and GemError.io when the font cannot be loaded.

Pass an empty regular path with no bold or italic path to restore the style or built-in font. The mapFontPath getter returns the path of the custom regular face, or the bold or italic one when only those are set, and an empty string when no custom font is set.

Inspect the style layers at a position​

Use getStyleLayerInfo on the GemMapController to find out which layers of the applied map style have content at a given coordinate, for example to tell whether the user tapped a label or an area:

final Coordinates coordinates = Coordinates(
latitude: 48.8566,
longitude: 2.3522,
);
mapController.centerOnCoordinates(coordinates, zoomLevel: 80);

// Layers of the applied style with content at the position, topmost first
final List<StyleLayerInfo> layers =
mapController.getStyleLayerInfo(coordinates);

if (layers.isEmpty) {
showSnackbar("No style layer at the position (view not ready?)");
} else {
showSnackbar(layers
.map((StyleLayerInfo layer) => '${layer.id}: ${layer.name}')
.join(', '));
}

The layers are returned topmost first. Each StyleLayerInfo carries the layer id and its name, which is the layer type, for example symbol for a label layer or polygon for an area layer. Only the layers currently visible in the view are considered, and the list is empty when no visible layer has content at the position or when the view is not ready yet.

Get notified about style changes​

The user can be notified when the style changes by providing a callback using the registerOnSetMapStyle method from the GemMapController:

controller.registerOnSetMapStyle((id, stylepath, viaApi){
print('The style with id $id and path $stylepath has been set. viaApi: $viaApi');
});

The callback provides:

  • id - the style id
  • stylepath - the path to the .style file
  • viaApi - indicates if the style was set via API