Only this pageAll pages
Powered by GitBook
1 of 45

v3

Loading...

Getting Started

Loading...

Loading...

Loading...

Loading...

Usage

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Plugins

Loading...

Loading...

Loading...

Loading...

Tile Servers

Loading...

Loading...

Loading...

Loading...

FAQs

Loading...

Loading...

Migration

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

flutter_map

Mapping package for Flutter, based off of 'leaflet.js'. Simple and easy to learn, yet completely customizable and configurable, it's the best choice for mapping in your Flutter app.

This documentation applies to v3 only!

Use the version selector in the top left to choose documentation suitable for your version.

Demonstration

This code snippet demonstrates everything you need for a simple map - of course, FlutterMap is much more customisable than just this!

return FlutterMap(
    options: MapOptions(
        center: LatLng(51.509364, -0.128928),
        zoom: 9.2,
    ),
    nonRotatedChildren: [
        AttributionWidget.defaultWidget(
            source: 'OpenStreetMap contributors',
            onSourceTapped: null,
        ),
    ],
    children: [
        TileLayer(
            urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
            userAgentPackageName: 'com.example.app',
        ),
    ],
);

Feature Highlights

Get Help

If you're not sure where to get help, feel free to ask anywhere, and we'll try to point you in the right direction.

General Support

If you're not sure how to do something, the best place to get help is on the Discord server! We're here to answer your questions as quickly as possible, so please give us as much information as you can! Please remember that we are volunteers, so we cannot guarantee (fast) support.

Use the link/button at the top of this page, or the link in the footer on all pages to join.

Bugs & Feature Requests

For suspected bugs or feature requests, visit the issue tracker on GitHub and ask away! We'll try to get back to you relatively quickly, but it may take longer for larger issues.

Due to time shortages and other internal matters, wait times for feature request implementations are currently extremely long and may not happen at all.

We'd love to have your contributions to add your own or others' pull requests!

Supports any* map style

We natively support any static raster tile server, including from a web server or even from the local file system or app asset store.

Stress-free setup

Migrating from a commercial library such as Google Maps has never been easier! No more complex platform-specific setup, no more API keys: just add a widget and you're done.

Wide ecosystem of plugins

In the unlikely event that flutter_map doesn't natively contain something you need, just check to see if there's a community maintained plugin that does what you need!

Add map features

Add polygons, polylines, and markers/pins to your map easily and quickly. Markers support displaying any widget you might want.

Additional Setup

All Platforms

This can then be imported like this in any required files:

import 'package:latlong2/latlong.dart';

Additionally, other plugins (see Plugins List) might require other setup and/or permissions.

Android

On Android, additional setup may be required. To access the Internet to reach tile servers, ensure your app is configured to use the INTERNET permission. Check (and if necessary add) the following lines in the manifest file located at '/android/app/src/main/AndroidManifest.xml':

AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET"/>

You may also need to do this in any other applicable manifests, such as the profile one, if not already in there.

It is recommended to also to expose the LatLng object used extensively throughout.

In the event that the LatLng object provided by this library conflicts with another, for example the one provided by Google Maps, you may need to .

install 'latlong2'
use the 'as' suffix

Recommended Options

Center (center)

Takes a LatLng object, specifying the latitude and longitude of the center of the map when it is first built. For example:

        center: LatLng(0.0, 0.0),

Defaults to LatLng(50.5, 30.51).

Zooms (zoom, minZoom, maxZoom)

Takes doubles, but should usually be set initially to integers (in double format).

zoom specifies what the zoom level of the map should be when it is first built, defaulting to level 13. maxZoom specifies what the maximum zoom level can be, and should depend on your use case and/or tile server. minZoom specifies what the minimum zoom level can be, and should usually be set to 0/null default.

        zoom: 13.0,
        maxZoom: 19.0,

Note that many tile servers will not support past a zoom level of 18. Always specify the maxZoom below the maximum zoom level of the server, to avoid your users seeing a void of grey tiles.

The OpenStreetMap Tile Server supports up to level 19, and a small amount of other servers support up to level 22.

Boundaries (bounds, maxBounds)

Takes LatLngBounds to restrict the map view within a rectangular area.

bounds is only effective on first build, and is an alternative to using center and zoom to initialise the map. maxBounds is persistent and prevents the view moving outside of the area. For example:

        bounds: LatLngBounds(
            LatLng(51.74920, -0.56741),
            LatLng(51.25709, 0.34018),
        ),
        maxBounds: LatLngBounds(
            LatLng(-90, -180.0),
            LatLng(90.0, 180.0),
        ),

will make the map center on London at first, and ensure that the gray void around the world cannot appear on screen (in the default projection).

Always specify your center within your boundaries to avoid errors. Boundaries will take preference over center.

Rotation (rotation)

Takes a double specifying the bearing of the map when it is first built. For example:

        rotation: 180.0,

will put the South of the map at the top of the device.

Defaults to 0(°).

Keep Alive (keepAlive)

If you are using a more complex layout in your application - such as using the map inside a ListView, a PageView, or a tabbed layout - you may find that the map resets when it appears/scrolls back into view. This option is designed to prevent that.

Takes a bool flag, toggling whether the internal map state should wantKeepAlive.

        keepAlive: true,

Defaults to false.

Overuse of this option may lead to performance issues.

It prevents the Flutter VM from freeing up as much memory, and it must remain processing any events that may happen to it.

will put the map at '' on first build, where the Prime Meridian and Equator intersect at 0 deg Latitude and 0 deg Longitude.

For an explanation of zoom levels, see the page.

Null Island
LogoIssues · fleaflet/flutter_mapGitHub

Tile Providers

... and Offline Mapping

This has a default of NetworkNoRetryTileProvider, which is recommended for most setups for better performance, unless your tile server is especially unreliable, or you need a local tile provider.

Custom TileProviders can be implemented by your application or other libraries. These may not conform to the usual rules above, and may additionally have their own parameters.

Network Tile Providers

Whilst not on the web, network tile providers can take a custom HttpClient/RetryClient, if you need to use it for whatever reason.

NetworkNoRetryTileProvider()

This is the default tile provider.

This tile provider uses the templateUrl to get the appropriate tile from the Internet, and it won't retry the request if it fails.

There is no guarantee about the default caching behaviour, but tiles should be cached until an application restart.

NetworkTileProvider()

This tile provider uses the templateUrl to get the appropriate tile from the Internet, but it will retry the request as specified in the RetryClient (which can be customised as needed when not on the web).

There is no guarantee about the default caching behaviour, but tiles should be cached until an application restart.

Local Tile Providers

These tile providers use the templateUrl to get the appropriate tile from the asset store of the application, or from a file on the users device, respectively

AssetTileProvider()

This tile providers uses the templateUrl to get the appropriate tile from the asset store of the application.

FileTileProvider()

This tile providers uses the templateUrl to get the appropriate tile from the a path/directory/file on the user's device - either internal application storage or external storage.

On the web, FileTileProvider() will automatically use NetworkImage() behind the scenes. This is not recommended. If you know you are running on the web platform, avoid using this tile provider.

Offline Mapping

Bundled Map Tiles

If you have a set of custom raster tiles that you need to provide to all your users, you may want to consider bundling them together, to make a them easier to deploy to your users. Note that this is different to the #caching section below.

There is essentially two options for doing this:

  • Using AssetTileProvider, you can bundle a set of map tiles and register them as an asset within your app's pubspec.yaml. This means that they will be downloaded together with your application, keeping setup simple, but at the expense of a larger application bundle size.

  • Using FileTileProvider, you can bundle a set of map tiles and store them on a remote web server, that can be downloaded from later. This means that the setup may be more complicated for users, but the application's bundle size will be much smaller.

Either way, the filesystem should be structured like this: 'offlineMap/{z}/{x}/{y}.png', where every .png image is a tile.

Caching & Bulk Downloading

However, using simpler packages in a DIY solution can be a better option in some cases. You'll need to implement a custom TileProvider backed by an alternative image provider or cache lookup system: see Creating New Tile Providers.

To help choose whether FMTC or DIY is more appropriate for your usecase, please see:

If you prefer to offer a set of map tiles to all your users before runtime, consider using the Bundled Map Tiles solution instead.

The tileProvider parameter in TileLayer takes a TileProvider object specifying a to use for that layer.

Network tile providers can take a Map<String, String> of custom headers. Note that the that is automatically generated will not override any 'User-Agent' header if specified here. On the web, the 'User-Agent' header is not sent, as the browser controls the user agent.

If you have a raster-format .mbtiles file, for example from TileMill, you should use to convert it to the correct structure first. Alternatively, you can use an external package such as '' to extract during runtime.

The provides advanced caching and bulk downloading capability, which handles many surrounding and supporting features for you and your app, with minimal implementation effort.

mbtilesToPngs
flutter_mbtiles_extractor
community maintained plugin flutter_map_tile_caching
user agent

Tile Layer

This page (and subpages) only talks about WMTS-supporting raster layers, which is the most common and default type of mapping.

For information about WMS-supporting layers or vector tiles, visit the WMS Usage page.

A tile layer displays raster map tiles in a grid pattern, from a tile source such as a remote server or file system. This might look something like this:

FlutterMap(
    options: MapOptions(),
    children: [
        TileLayer(
          urlTemplate: "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
          userAgentPackageName: 'dev.fleaflet.flutter_map.example',
        ),
    ],
),

You must comply to your tile server's ToS. Failure to do so may result in you being banned from their services.

This package is not responsible for your misuse of another tile server.

Layers

The OpenStreetMap Tile Server (as used above) can be . Other servers may have different terms.

As briefly described in , the children property takes a list of Widgets, which will be stacked on top of each other (last on top). These can be any Widget, such as a FutureBuilder or StreamBuilder, but are usually Layers which are provided by this library or plugins.

There is also the nonRotatedChildren property, which work similarly as their 'rotatable' counterpart, but - as the name suggests - do not get rotated as the map gets rotated. For example, the should be used inside nonRotatedChildren instead of children, as it needs to remain vertical and therefore readable.

As a minimum, all maps should have a , as this is what actually displays any map. Other layers are available, such as markers/waypoints and lines.

found here
Recommended Options
Other Options
Tile Layer
AttributionWidget

Installation

This is the recommended method of installing this package as it ensures you only receive stable versions, and you can be sure pub.dev is reliable. It also keeps the size of your pubspec.yaml small.

Just import the package as you would normally, from the command line:

This should automatically import the latest version of the package and create an entry for it in your pubspec.yaml. Otherwise follow the old method and add the latest version of the 'flutter_map' dependency to the pubspec.yaml manually.

If you urgently need the latest version, a specific branch, or a specific fork, you can use this method.

Commits available from Git (GitHub) may not be stable. Only use this method if you have no other choice.

Import

After installing the package, import it into the necessary files in your project:

Before continuing with usage, make sure you comply with the appropriate rules and ToS for your server. Some have stricter rules than others. This package or the creator(s) are not responsible for any violations you make using this package.

From

From

First, use , then add the following lines to your pubspec.yaml file, as a root object:

This package should now be mostly setup! Make sure you follow through with the appropriate instructions for your platform.

flutter pub add flutter_map
pubspec.yaml
dependency_overrides:
    flutter_map:
        git:
            url: https://github.com/fleaflet/flutter_map.git
            # ref: main 
import 'package:flutter_map/flutter_map.dart'; // Suitable for most situations
import 'package:flutter_map/plugin_api.dart'; // Only import if required functionality is not exposed by default
Additional Setup
From pub.dev
pub.dev
github.com

Raster vs Vector Tiles

It is important to note that 'flutter_map' only supports raster tiles natively. Vector tiles can be used with a community maintained plugin.

This is described in more detail at the bottom of this page.

There are 2 main types of tiles a server can serve: raster and vector; each has their own advantages and drawbacks. This page is designed to help you choose a type for your app, and help you use vector tiles if you choose to.

Raster Tiles

Raster tiles are the 'older' type of tile, and are raster images (usually .png or .jpg). These tiles are good because they can render quickly and easily, can be viewed without special software, and are readily available from most mapping services. As such, this makes them the popular choice for beginners.

However, raster tiles cannot be easily themed: a theme needs a whole new set of map tiles. This makes apps using light and dark themes have mismatching maps. As well as this, raster tiles usually have larger file sizes meaning slower download times, and they can become blurred/pixelated when viewed at a larger scale: a problem for users when zooming between zoom levels. Another issue is that shapes/text inside tiles cannot be rotated, hence the name 'static tiles': therefore, rotating the map will not rotate the name of a road, for example.

Vector Tiles

Vector tiles can be considered the 'newer' standard. These images might contain a specialised format (such as .pbf) dictating the mathematics and coordinates used to draw lines and shapes. Because these tiles are drawn at render time instead of at request/server time, theming can be used to make the map fit in better with an app's theme. The math-based image means that the images/tiles can be scaled without any loss of clarity.

However it does add complexity to the rendering process as each element needs to be parsed and painted individually, meaning an impact to performance. Text elements and certain shapes can also be rotated (unlike raster tiles) to match the user's orientation, not the orientation of the map; but calculating this rotation needs to be done every frame, meaning an even larger impact on performance.

Using Vector Tiles

How Does It Work?

If you don't know about standard map things, such as the latitude/longitude system and projections, you should probably read about these first!

This library is similar to most other mapping libraries in other languages, so this applies to most other mapping libraries as well.

A mapping library is usually just a wrapper for a particular language that handles requests to servers called 'tile servers', and displays it in an interactive view for the user.

What is a Tile Server?

A tile server is a server accessible on the Internet by everyone, or by only people holding the correct API key.

There are four main types of server configuration, two of which are used together by any server: WMS or WMTS (aka. CARTO) & vector or raster. This wiki will focus on WMTS raster servers, such as the main OpenStreetMaps server, as it is the most commonly used option and is easier to setup and explain for beginners, but you can read about the options for WMS later on in this wiki. At the moment, support of vector tiles is limited, but experimental functionality can be added through an existing community maintained plugin.

Simplified, the server holds multiple images in a directory structure that makes it easy to find tiles without searching for references in a database beforehand (see below). These images put together make up the whole world, or area that that tile server supports. One tile is usually really small when rendered, under 20KB for most tiles. However, the entire planet data consumes 1.5TB when un-rendered and uncompressed from the 110GB download archive. When all tiles are rendered, they add up to over 54TB! Most servers render tiles on-the-fly to get around this.

'Slippy Map' Convention

The standard Slippy Map path looks like this: '/zoom/x/y.png' or '/x/y/zoom.png'. To note, the image format does not have to be '.png', tile servers also commonly serve as '.jpg' images.

You may also see '/?x={x}&y={y}&zoom={z}', which isn't quite the same as the Slippy Map convention, but it works in essentially the same way, so the below text still applies.

Zoom

X & Y

These images show the mathematics required to convert between Latitude and Longitude & the x/y/z format and vice-versa respectively. All credit for the above images goes to the Open Street Maps foundation.

Tile Providers

In this 'flutter_map' package, the classes that conduct this maths to get these tiles are called 'tile providers'.

However, these do a lot more than just the maths. They do the maths, format the appropriate URL, potentially stagger the URL (not to get rate limited by the browser or engine), make the request, get the image, process (and potentially store) the image and finally give it back to the main process to paint onto the map for the user to see.

Unless you choose to implement your own custom tile provider, you should never need to handle this yourself.

This can be quite confusing for newcomers!

Within this library, 'tile providers' use 'tile servers' to retrieve tiles from the Internet. On the other hand, 'tile servers' and external sites usually use 'tile providers' to mean 'tile servers'!

Map Layers

Once the tile provider has dealt with the tile, it sends it to a map layer to get painted onto the map. This can be done using canvases (such as in HTML5 for the web), or, in the case of 'flutter_map', Flutter widgets.

The map layers also handle user interaction, such as panning, zooming, rotating and tapping.

Due to the complications mentioned above, 'flutter_map' does not natively support vector tiles. However, vector tiles can be used with a to do this.

If you want a truly British insight into this, look no further than: & . Otherwise I'd recommend something else.

The main tile server that's free to use and open-source is the Open Street Maps tile server, as mentioned above, a server which provides access to millions of tiles covering the whole Earth. that get updated and maintained by the general public. You can .

The , but this page provides some basics, roughly copied from that page.

Zoom refers to the zoom level. 1 is the lowest zoom level and contains the whole world in one tile. The higher the number, the more the zoom, and the more the detail, and therefore the less space covered. You can read more about this at . Most servers go up to 18, some up to 19, but no servers (as of writing) have a maximum limit above 22.

X and Y are values corresponding to the longitude and latitude of a location, however they are not actual longitude and latitude. See .

For more information about setting up a tile provider within the API, see .

community maintained plugin (vector_map_tiles)
How Does It Work?
tile provider
Tile Providers
https://youtu.be/3mHC-Pf8-dU
https://youtu.be/jtBV3GgQLg8
find other 'semi-endorsed' public servers here
slippy map convention is documented extensively here
wiki.openstreetmap.org/wiki/Zoom_levels
wiki.openstreetmap.org/wiki/Slippy_map_tilenames
Lat/Lng to x/y/z
x/y/z to Lat/Lng
points

Marker Layer

You can add markers to maps to display specific points to users using MarkerLayer().

FlutterMap(
    options: MapOptions(),
    children: [
        MarkerLayer(
            markers: [
                Marker(
                  point: LatLng(30, 40),
                  width: 80,
                  height: 80,
                  builder: (context) => FlutterLogo(),
                ),
            ],
        ),
    ],
),

Excessive use of markers or use of complex markers will create performance issues and lag/'jank' as the user interacts with the map. See for more information.

Markers (markers)

As you can see MarkerLayerOptions() accepts list of Markers which determines render widget, position and transformation details like size and rotation.

Property
Type
Defaults
Description

point

LatLng

required

Marker position on map

builder

WidgetBuilder

required

Builder used to render marker

width

double

30

Marker width

height

double

30

Marker height

rotate

bool?

false*

If true, marker will be counter rotated to the map rotation

rotateOrigin

Offset?

The origin of the marker in which to apply the matrix

rotateAlignment

AlignmentGeometry?

The alignment of the origin, relative to the size of the box

anchorPos

AnchorPos?

Point of the marker which will correspond to marker's location

If you need to use a large number of markers, an existing might help.

community maintained plugin (flutter_map_marker_cluster)
Pub.dev

Polyline Layer

You can add lines to maps to display paths/ways made out of points to users using PolylineLayer().

FlutterMap(
    options: MapOptions(),
    children: [
        PolylineLayer(
            polylineCulling: false,
            polylines: [
                Polyline(
                  points: [LatLng(30, 40), LatLng(20, 50), LatLng(25, 45),],
                  color: Colors.blue,
                ),
            ],
        ),
    ],
),

Due to the nature of the Earth being a sphere, drawing lines perfectly requires large amounts of difficult maths that may not behave correctly when given certain edge-cases.

Avoid creating large polylines, or polylines that cross the edges of the map, as this may create undesired results.

Excessive use of polylines or use of complex polylines will create performance issues and lag/'jank' as the user interacts with the map. See for more information.

You can try the below methods to try to reduce the lag:

  • Keep saveLayers set to false (which is default). This will reduce rendering times, however it will also reduce the visual quality of the line at intersections.

  • Enable polylineCulling. This will prevent the calculation and rendering of lines outside of the current viewport, however this may not work as expected in all situations.

Polylines (polylines)

As you can see PolylineLayerOptions() accepts list of Polylines. Each determines the shape of a polyline by defining the LatLng of each point. 'flutter_map' will then draw a line between each coordinate.

Property
Type
Defaults
Description

points

List<LatLng>

required

The coordinates of each point

strokeWidth

double

1.0

Width of the line

color

Color

Color(0xFF00FF00)

Fill color

borderStrokeWidth

double

0.0

Width of the border of the line

borderColor

Color

Color(0xFFFFFF00)

Color of the border of the line

gradientColors

List<Color>?

List of colors to make gradient fill instead of a solid fill

colorsStop

List<double>?

List doubles representing the percentage of where to START each gradient color along the line

isDotted

bool

false

Whether to make the line dotted/dashed instead of solid

Converting Formats

You may have a polyline with 'Google Polyline Encoding' (which is a lossy compression algorithm to convert coordinates into a string and back). These are often returned from routing engines, for example. In this case, you'll need to decode the polyline to the correct format first, before you can use it in a Polyline's points argument.

import 'package:latlong2/latlong.dart';
export 'package:google_polyline_algorithm/google_polyline_algorithm.dart'
    show decodePolyline;

extension PolylineExt on List<List<num>> {
  List<LatLng> unpackPolyline() =>
      map((p) => LatLng(p[0].toDouble(), p[1].toDouble())).toList();
}

You can then use the package and the above snippet by doing:

import '<code_snippet_path>'

decodePolyline('<encoded-polyline>').unpackPolyline(); // Returns `List<LatLng>` for a map polyline

Options

The options property takes a MapOptions() object.

This is where you'll configure most of your global map settings, but not settings that depend on, or affect a specific, map layer.

None of the options are required, but the options property on the FlutterMap() is required.

Simplify the polyline by reducing the number of points within it. This will reduce calculation times, however it will make the line less precise. This is recommended, for example, when zoomed further out. You may be able to use an external Flutter library for this, called .

One way to accomplish this is to use another Flutter library called , together with a custom method. You can use the code snippet below, which can just be pasted into a file and imported whenever needed:

'simplify'
'google_polyline_algorithm'
FlutterMap(
    options: MapOptions(
        ...
    ),
);
Recommended Options
Other Options
likes
stars

Circle Layer

We're writing this documentation page now! Please hold tight for now, and refer to older documentation or look in the API Reference.

You can add circle polygons to maps to users using CircleLayer().

FlutterMap(
    options: MapOptions(),
    children: [
        CircleLayer(
            circles: [],
        ),
    ],
),

Due to the nature of the Earth being a sphere, drawing lines perfectly requires large amounts of difficult maths that may not behave correctly when given certain edge-cases.

Avoid creating large polygons, or polygons that cross the edges of the map, as this may create undesired results.

Excessive use of circles will create performance issues and lag/'jank' as the user interacts with the map. See for more information.

Other Options

Visit the Full API Reference for the full list of available options

Interactivity Settings (interactiveFlags)

Takes an integer bitfield, which can be treated similar to enumerables. For example:

        InteractiveFlag.all & ~InteractiveFlag.rotate

allows/enables all interactions except for rotation (keeping the map at the heading specified by rotation).

The flags below are available:

Flag
Description

all

Enables all interactions

none

Disables all interactions

drag

Enables panning with one finger

pinchMove

Enables panning with two or more fingers

flingAnimation

Enables fling animation when drag/pinchMove have enough 'Fling Velocity'

pinchZoom

Enables zooming with a pinch gesture

doubleTapZoom

Enables zooming with a double tap (prevents onTap from firing)

rotate

Enables rotating the map with a twist gesture

Use & for 'AND' logic and ~ for 'NOT' logic. Combining these two gates, as shown in the example, can lead to many combinations, each easy to put together.

Defaults to enabling all interactions (all).

Scroll Wheel Settings (enableScrollWheel & scrollWheelVelocity)

Used together to enable scroll wheel scrolling, and set it's sensitivity/speed.

The first parameter takes a bool, enabling or disabling scroll wheel zooming. The second takes a double, which is used as a multiplier for changing the zoom level internally.

        enableScrollWheel: true,
        scrollWheelVelocity: 0.005,

Defaults to true and 0.005.

When Position Changed (onPositionChanged)

Takes a function with two arguments. Gets called whenever the map position is changed, even if it is not changed by the user.

        onPositionChanged: (MapPosition position, bool hasGesture) {
            // Your logic here. `hasGesture` dictates whether the change
            // was due to a user interaction or something else. `position` is
            // the new position of the map.
        }

When Map Tapped (onTap)

Takes a function with one argument. Gets called whenever the the user taps/clicks/presses on the map.

        onTap: (TapPosition position, LatLng location) {
            // Your logic here. `location` dictates the coordinate at which the user tapped.
        }

When Map Ready (onMapReady)

See Usage In initState() before using this callback.

This callback can be registered if you need to do something with the map controller as soon as the map is available and initialized; generally though it isn't needed and the map is available after first build.

Takes a function with zero arguments. Gets called from the initState() method of the FlutterMap.

Controller

The mapController property takes a MapController, and whilst it is optional, it is strongly recommended for any map other than the most basic. It allows you to programmatically interact with the map, such as panning, zooming and rotating.

Initialisation

To use a MapController, it must initialised and then passed to the FlutterMap. This attaches them until the widget is destroyed/disposed.

final mapController = MapController();

@override
Widget build(BuildContext context) =>
    FlutterMap(
        mapController: mapController,
        ...
    );

Usage In initState()

It is a fairly common requirement to need to use the MapController before the map has been built, or to initialise a listener for one of it's streams inside the initState() StatefulWidget method. Unfortunately, this is not possible, as the map must be built for the controller to be attached.

Recommended Usage

Luckily, Flutter provides methods to wait until the first frame has been built, which usually means the FlutterMap widget will have been built (see exception circumstances below). This makes it trivially easy to implement the desired behaviour.

Recommended Usage
@override
void initState(){
    super.initState();
    WidgetsBinding.instance.addPostFrameCallback((_) {
        // Use `MapController` as needed
    });
}

Alternative Usage

For simplicity and readability, it is not recommended to use this method unless needed in your situation, although there should be little technical difference.

In some cases, the FlutterMap widget may not have been built on the first frame - for example when using a FutureBuilder around the map.

In this case, an alternative method is required to use the MapController on build. This method uses the When Map Ready (onMapReady) callback.

Alternative Usage
@override
Widget build(BuildContext context) =>
    FlutterMap(
        mapController: mapController,
        options: MapOptions(
            onMapReady: () {
                // Use `MapController` as needed
            },
        ),
    );

Available Methods

#map-widget

Base Widget

FlutterMap(
    mapController: _mapController,
    options: MapOptions(),
    children: [],
    nonRotatedChildren: [],
);

Placement Recommendations

It is recommended to make the map as large as possible, to allow it to display a lot of useful information easily.

As such, we recommend using a depth-based layout (eg. using Stacks) instead of a flat-based layout (eg. using Columns). The following 3rd party packages might help with creating a modern design:

If you must restrict the widget's size, you won't find a height or width property. Instead, use a SizedBox or Column/Row & Expanded.

Do not use nonRotatedChildren to enforce a non-rotatable map. Instead, use .

nonRotatedChildren

Optional

Similar to children, but these don't rotate or move with the other layers.

options (MapOptions)

Required

Configure options that don't directly affect the appearance of the map, such as starting location and maximum zoom limit.

mapController

Optional

Attach a controller object to control the map programatically, including panning and zooming.

children

Required

Takes a List of Widgets (usually a dedicated 'layer') to display on the map, such as tile layers or polygon layers,

https://pub.dev/packages/backdrop
https://pub.dev/packages/sliding_up_panel
https://pub.dev/packages/material_floating_search_bar
interactiveFlags inside MapOptions

Plugins List

There are many independently maintained 'plugins' created by the 'flutter_map' community that give extra, prebuilt functionality, saving you even more time and potentially money.

Some pages in this documentation provide direct links to these plugins to make it easier for you to find a suitable plugin.

However, if you're just browsing, a full list is provided below (in no particular order), containing many of the available plugins. You can click on any of the tiles to visit its GitHub repo or pub.dev package.

Although these plugins have been checked by 'flutter_map' maintainers, we do not accept responsibility for any issues or threats posed by independently maintained plugins.

Use plugins at your own risk.

There is no guarantee that any of these plugins will support the latest version of flutter_map.

Please remain patient with the plugin authors/owners.

Many plugins provide multiple methods to achieve similar goals. It is recommended to read the documentation of each potential plugin before using it in your project, as they might have slightly different feature sets or stability.

For example, there are two plugins that provide GeoJson parsing, and there are three plugins that provide marker clustering.

Miscellaneous

From more layers to whole heaps of new functionality, it's all here - assuming it's not in one of the other sections!

Marker Clustering

Marker clustering groups markers together under bigger markers when zoomed further out, decluttering your UI and giving a performance boost.

Better Markers

Better Polylines & Polygons

Parsing & Creating Map Features

Using Mapbox

'flutter_map' is in no way associated or related with Mapbox.

Mapbox is a popular pay-as-you-go tile provider solution, especially for commercial applications. However, setup with 'flutter_map' can be a bit finicky, so this page is here to help you get going with Mapbox. Note that these methods use up your 'Static Tiles API' quota.

Pre-made Styles

Custom Styles

Then make the map style public, and open the share dialog, as seen below:

Scroll to the bottom of the dialog, and select Third Party. Then from the drop down box, select 'CARTO':

You'll then need to copy the URL and use it in 'flutter_map', like in the code below.

Usage

You should remove the 'access_token' (found at the end of the URL, usually beginning with 'pk.') from the URL for readability. Instead, pass it to additionalOptions.

FlutterMap(
    options: MapOptions(
      center: LatLng(51.5, -0.09),
      zoom: 13.0,
    ),
    nonRotatedChildren: [
        // This does NOT fulfill Mapbox's requirements for attribution
        // See https://docs.mapbox.com/help/getting-started/attribution/
        AttributionWidget.defaultWidget(
            source: '© Mapbox © OpenStreetMap',
            onSourceTapped: () async {
                // Requires 'url_launcher'
                if (!await launchUrl(Uri.parse("https://docs.mapbox.com/help/getting-started/attribution/"))) {
                    if (kDebugMode) print('Could not launch URL');
                }
            },
        )
    ],
    children: [
      TileLayer(
        urlTemplate: "https://api.mapbox.com/styles/v1/<user>/<tile-set-id>/tiles/<256/512>/{z}/{x}/{y}@2x?access_token={access_token}",
        additionalOptions: {
            "access_token": "<ACCESS-TOKEN>",
        },
        userAgentPackageName: 'com.example.app',
      ),
    ],
);

Mapbox's Maps home page: Mapbox's Maps pricing page: Mapbox's Maps documentation:

Mapbox offers a variety of ready-made map styles that don't require customization. An example URL can be found in .

First, create a custom map Style in the Studio. You can personalise to your heart's content, or leave it at default for a more vanilla feeling. You'll also need an .

Please note that choosing either 256x256 or 512x512 (default) pixel tiles will impact pricing: see .

flutter_osrm (JaffaKetchup)

Suite of tools for working with routing information from an OSRM server

flutter_map_tile_caching (JaffaKetchup)

Advanced and highly-configurable caching solution, with support for bulk downloading

vector_map_tiles (greensopinion)

Suite of tools and layers for working with vector maps and style files

lat_lon_grid_plugin (matthiasdittmer)

A latitude longitude grid layer/overlay

flutter_map_animations (TesteurManiak)

Replacement for MapController which provides animated movement alternatives

flutter_map_supercluster (rorystephenson)

Superfastâ„¢ marker clustering solution, without animations

flutter_map_marker_cluster (lpongetti)

Beautiful and animated marker clustering solution

flutter_map_radius_cluster (rorystephenson)

Marker clustering solution with support for async marker searching within a radius

flutter_map_location_marker (tlserver)

Provides a prebuilt solution to display the user's location and heading/direction

flutter_map_marker_popup (rorystephenson)

Provides a prebuilt solution to display a popup above a marker when tapped

flutter_map_floating_marker_titles (androidseb)

Enables the display of 'floating' titles over markers

flutter_map_fast_markers (KanarekApp)

Improves performance of markers by painting directly onto canvas

flutter_map_line_editor (ibrierley)

Enables better dynamic editing of Polylines and Polygons

line_animator (ibrierley)

Interpolates along a set of points, allowing gradual drawing of lines and animating moving markers

flutter_map_tappable_polyline (OwnWeb)

Provides an onTap callback for Polylines

flutter_map_geojson (jozes)

Suite of tools to parse data in the GeoJson format into map features

polybool (mohammedX6)

Suite of tools to operate on polygons, such as union, intersection, and difference

geojson_vector_slicer (ibrierley)

Suite of tools to display GeoJson, vector tiles, and marker clusters, using sliced vector tiles

mapbox.com/maps
mapbox.com/pricing#maps
docs.mapbox.com/api/maps/static-tiles
the example here
access token
the documentation
Open PRs

Making A Plugin

There are many independently maintained plugins created by the 'flutter_map' community that give extra, prebuilt functionality, saving you even more time and potentially money.

Unfortunately, you may need more niche functionality that hasn't been provided by an existing plugin or by 'flutter_map' itself. Alternatively, you may have found a gap in functionality that not everyone will need, but some people will: in this case, it's likely the maintainers will ask you to submit a plugin instead of a pull request.

Plugins can add/change a wide variety of functionality, so this guide is not exhaustive. However, it will help with the most common requirements. Each subpage covers a specific part of the plugin API, and the section below sets out requirements for plugins to be accepted into the list.

Submitting A New Plugin

If you've made your own plugin that you're willing to share, you can add it to this list by creating a pull request in GitHub. We're always looking forward to see what you've made!

When submitting a plugin & PR, please ensure the plugin:

  • preferably includes 'flutter_map_' in the name

  • preferably available via a pub.dev installation

  • includes a runnable example, and/or screenshots or recordings

  • has a description that accurately and concisely represents your plugin

If you want to provide extra assistance to your users in a shared space, consider the official 'flutter_map' Discord server! Join using the link at the bottom of this page, and ping '@Github Maintainer' to be added to the 'Plugin Owner' role. You can then be easily identified and provide help or announcements in a dedicated plugins channel.

Open Issues

Map Controller Issues

These issues appear significantly less after v2.1.0, due to the reworking of the MapController lifecycle.

If you are experiencing these errors, please consider updating to this version or later.

This class of errors is usually caused by mis-configuring MapControllers (see Controller), or using them in complex layouts.

If you're having these issues - which can manifest as LateInitializationErrors and/or BadState errors - there are a few things you can try to help out:

  • Fully read the Controller page, and choose the right implementation/usage for your situation.

  • In complex layouts, such as with PageViews or ListViews, use the Keep Alive (keepAlive) property.

  • If sharing the map controller, for example through Provider, make sure that the shared controller is initialised and destroyed/uninitialised at the same time as the FlutterMap.

Other Options

Visit the Full API Reference for the full list of available options

Subdomains (subdomains)

Takes a list of strings specifying the available subdomains. For example:

One will be chosen differently every request by the tile provider to replace the '{s}' part of the urlTemplate.

If you are not sure of the correct values for your server, don't specify anything. For example, the urlTemplate used in the example above will work without the '{s}' part and any subdomains specified.

This option is no longer recommended in many cases, and it can be detrimental to performance in some cases.

Other servers may still use these subdomains to bypass browser connection concurrency and perform load balancing, in which case, this property is recommended.

Tile Bounds (tileBounds)

Takes a LatLngBounds to restrict the layer to only loading tiles within that area. For example:

will restrict the tiles to only loading Egypt (a square-ish country). Note that the map can still be moved freely outside of this range.

An example use-case might therefore be loading a specialised map for a region and just a basic map style elsewhere (different urlTemplates). In this case, the bounded layer should go beneath the unbounded layer. Setting backgroundColor: Colors.transparent is also necessary on the bounded layer to ensure the other layer is visible elsewhere.

Error/Fallback Tile (errorImage)

will use a sea tile on every tile that cannot be fetched.

This is an optional parameter that has no default. If this is not specified, and tiles are unable to be fetched, then the background color.

Tile Size (tileSize)

Takes a double number specifying the width and height (in pixels) of each tile. As tiles are always square, only one number is needed.

This defaults to 256, as most tile servers serve 256x256px tiles.

Custom Tile Builder (tileBuilder)

Takes a callback function, in the format Widget Function(BuildContext context, Widget tileWidget, Tile tile). For example:

will show the tile's coordinate on the tile.

There is also tilesContainerBuilder available, which works slightly differently, but is recommended when the same builder can be used on every tile, for performance reasons.

There are predefined tile builders available, such as a dark mode emulator and a loading time debugger.

Reset Stream (reset)

This option is significantly less important and useful after v3.0.0. Please consider updating to that version or later.

Takes a Stream<void>?, that causes the layer to 'reset' when an event is received. This might be necessary after updating the templateUrl. For example:

Major servers - such as OpenStreetMap's - support HTTP/2 & HTTP/3, which don't require subdomain aliases to increase browser connection concurrency. Using a single URL improves performance and ability to cache. For more information, see .

Takes an ImageProvider, such as a NetworkImage, to use if the tile cannot be fetched using the templateUrl. The size of the returned image should be the same as the . For example:

        subdomains: ['a', 'b', 'c'],
        tileBounds: LatLngBounds(
            LatLng(32.2934590056236, 24.328924534719548),
            LatLng(21.792152188247265, 37.19854583903912),
        ),
        errorImage: const NetworkImage('https://tile.openstreetmap.org/18/0/0.png'),
        tileBuilder: (context, widget, tile) =>
          Stack(
            fit: StackFit.passthrough,
            children: [
              widget,
              Center(
                child:
                  Text('${tile.coords.x.floor()} : ${tile.coords.y.floor()} : ${tile.coords.z.floor()}'),
              ),
            ],
          );
       reset: resetController.stream,
  
  // Elsewhere     
  final StreamController<void> resetController = StreamController.broadcast();
  void resetMap() => resetController.add(null);
this OpenStreetMap operations post
tile size

Using Thunderforest

'flutter_map' is in no way associated or related with Thunderforest (or Gravitystorm Limited).

Thunderforest is a popular tiered-payment (with free tier) tile provider solution, especially for generic mapping applications. Note that using 'flutter_map' uses up your 'Map Tiles API' requests.

Thunderstorm's home page: Thunderstorm's pricing page: Thunderstorm's documentation page:

thunderforest.com
thunderforest.com/pricing
thunderforest.com/docs/map-tiles-api

Frequently Asked Questions

If you have a question you'd like to add to this page, please let us know over on the Discord server!

You should also read the How Does It Work? page for a more generalised overview of the most important facts.

Custom Tile Styles

Unfortunately, this library cannot provide this functionality.

Raster tiles are pre-rendered by the tile server, and cannot be changed on the fly. Filters can be applied, such as an emulated dark mode, but these effects do not look great. This is a limitation of the technology, not this library.

However, tilesets can be styled. This is the most effective way of using custom styles. These methods may help you with this:

  • You may wish to use a commercial service like Mapbox Studio, which allows you to style multiple tilesets. See Using Mapbox.

  • Alternatively, you can experiment with vector tiles. These are not pre-rendered, and so allow any style you desire to be applied on the fly. See Vector Tiles.

  • Your last option is to serve tiles yourself. See Other Options.

We're adding questions here as we get them!

Recommended Options

URL Template (urlTemplate)

This parameter is not strictly required, but the map is essentially useless without it specified with a valid URL.

Takes a string that is a valid URL, which is the template to use when the tile provider constructs the URL to request a tile from a tile server. For example:

will use the OpenStreetMap Tile Server.

You must comply to your tile server's ToS. Failure to do so may result in you being banned from their services.

This package is not responsible for your misuse of another tile server.

The '{s}', '{z}', '{x}' & '{y}' parts indicate where to place the subdomain, zoom level, x coordinate, and y coordinate respectively. Not providing at least the latter 3 parts won't necessarily throw an error, but the map won't show anything.

Package Name (userAgentPackageName)

Takes a String, which should be the unique package name (eg. com.example.app). For example:

This string is used to construct a 'User-Agent' header, sent with all tile requests (on platforms other than the web, due to Dart limitations), necessary to prevent blocking by tile servers.

Constructed agents are in the format: 'flutter_map (packageName)'. If the package name is not specified, 'unknown' is used in place.

Although it is not required, not specifying the correct package name will/may group your applications traffic with other application's traffic. If the total traffic exceeds the server's limits, they may choose to block all traffic with that agent, leading to a 403 HTTP error.

Tile Provider (tileProvider)

For more information, see:

Retina Mode (retinaMode)

If true, the providers should request four tiles of half the specified size and a bigger zoom level in place of one to utilize the high resolution. In this case, you should set MapOptions's maxZoom should be maxZoom - 1 instead.

For example, this is the recommended setup:

Opening the Sharing dialog
Retrieving the appropriate URL
Routing/Navigation

Routing is currently out-of-scope for 'flutter_map'. However, if you can get a list of coordinates from a 3rd party, then you can use the Polyline Layer to show it!

A good open source option is , but if you want higher reliability and more functionality such as real-time based routing, you may want to try a commercial solution such as Mapbox or Google Maps.

Animated MapController

It's possible to animate the movements made by a MapController, although this isn't implemented in this library.

For an example of how to do this, please see the .

The OpenStreetMap Tile Server (as used above) can be . Other servers may have different terms.

A bool flag to enable or disable (default) makeshift retina mode, recommended on supporting devices. If the tile server supports retina mode natively ('@2' tiles), you should use them instead, by including the '{r}' placeholder in the .

OSRM
example app's Animated Map Controller page
        urlTemplate: "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
        userAgentPackageName: 'com.example.app',
        retinaMode: MediaQuery.of(context).devicePixelRatio > 1.0,
URL Template (urlTemplate)

WMS Usage

We're writing this documentation page now! Please hold tight for now, and refer to older documentation or look in the API Reference.

Creating New Layers

Creating a new map layer is just as easy as it is to create a normal StatelessWidget or StatefulWidget.

Only one method call is needed to 'connect' the widget to the map state: FlutterMapState.maybeOf(). This call does two important things:

  • Cause the widget/layer to rebuild automatically when required (if in the build method)

  • Expose the map's internal state, meaning that it's information (such as zoom) can be accessed

You can see an example of how this is done below:

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

  @override
  Widget build(BuildContext context) {
    final mapState = FlutterMapState.maybeOf(context)!;
    // Use `mapState` as necessary, for example `mapState.zoom`
  }
}

Attempting to use the widget above outside of a FlutterMap widget will result in an error.

The FlutterMapState.maybeOf method will return null, because it cannot locate a parent/inherited state, and therefore cause a null exception.

found here
Tile Providers

Attribution Layer

Before publishing your app to users, you should credit the tile server you use, this library, and potentially and plugins you use.

FlutterMap(
    options: MapOptions(),
    nonRotatedChildren: [
      AttributionWidget.defaultWidget(
        source: '© OpenStreetMap contributors',
        onSourceTapped: () {},
      ),
    ],
),

Please credit flutter_map, it helps us to gain more developers that we can help!

Default Builder

The default builder, as shown above, can be used to get a classic attribution box appearance quickly without much setup. Just add a source and a function (if you want a clickable link to appear), and 'flutter_map' automatically gets credited.

Custom Builder

Alternatively, create your own box from scratch by omitting the defaultWidget constructor from the widget. Then you can build a custom widget as you would normally.

Polygon Layer

You can add polygons to maps to display shapes made out of points to users using PolygonLayer().

FlutterMap(
    options: MapOptions(),
    children: [
        PolygonLayer(
            polygonCulling: false,
            polygons: [
                Polygon(
                  points: [LatLng(30, 40), LatLng(20, 50), LatLng(25, 45),],
                  color: Colors.blue,
                ),
            ],
        ),
    ],
),

Due to the nature of the Earth being a sphere, drawing lines perfectly requires large amounts of difficult maths that may not behave correctly when given certain edge-cases.

Avoid creating large polygons, or polygons that cross the edges of the map, as this may create undesired results.

Excessive use of polygons or use of complex polygons will create performance issues and lag/'jank' as the user interacts with the map. See for more information.

To improve performance, try enabling polygonCulling. This will prevent the calculation and rendering of polygons outside of the current viewport, however this may not work as expected in all situations.

Polygons (polygons)

As you can see PolygonLayerOptions() accepts list of Polygons. Each determines the shape of a polygon by defining the LatLng of each corner. 'flutter_map' will then draw a line between each coordinate, and fill it.

Property
Type
Defaults
Description

points

List<LatLng>

required

The coordinates of each vertex

holePointsList

List<List<LatLng>>?

The coordinates of each vertex to 'cut-out' from the shape

color

Color

Color(0xFF00FF00)

Fill color

borderStrokeWidth

double

0.0

Width of the border

borderColor

Color

Color(0xFFFFFF00)

Color of the border

disableHolesBorder

bool

false

Whether to apply the border at the edge of 'cut-outs'

isDotted

bool

false

Whether to make the border dotted/dashed instead of solid

label

String?

Text to display as label in center of polygon

labelStyle

TextStyle

TextStyle()

Custom styling to apply to the label

labelPlacement

PolygonLabelPlacement

PolygonLabelPlacement.polylabel

Where to place the label in the polygon

More Polygon Operations

'flutter_map' doesn't provide any public methods to manipulate polygons, as these would be deemed out of scope.

To v2.0.0

This update brings major breaking changes. Please refer to the sections below for information on how to fix problems you may encounter.

Deprecated NonCachingNetworkTileProvider in favour of NetworkNoRetryTileProvider

The old TileProvider was deprecated due to the misleading name and internal refactoring.

The provider did indeed provide some basic, unreliable, caching, and therefore the old name was incorrect. Additionally, other providers used a similar internal implementation, which provided the same caching, but did not also include 'NonCaching' in the name.

To fix warnings, change all references to the new provider. No functionality will have been lost in this transfer.

This deprecated API will be removed in the next minor update.

TileProviders are no longer constant (const)

Due to internal refactoring, and the addition of the headers options, all built-in providers are no longer applicable to have the prefix keyword const.

To fix errors, remove the const keywords from the necessary locations.

updateInterval and tileFadeInDuration are now Durations

Previously, these parameters within the TileLayerOptions constructor were specified in an integer number of milliseconds.

To fix errors, convert the millisecond time into a Duration object.

Additionally, you should implement Package Name (userAgentPackageName)as soon as possible, to prevent potential future blocking.

To v3.0.0

This update brings major breaking changes for all users.

We apologise for any difficulty this may cause and time you may spend migrating.

However, this update is a part of our aim to simplify this library, and should improve stability, readability, and performance for you in the long term. In addition, this will make the library much easier to maintain and add new functionality to through plugins and future features.

Application Migration

Please refer to the sections below for information on how to migrate your application. This will contain the changes that most users may need to make, but not all changes.

This version requires a minimum of Flutter 3.3.0. Use flutter upgrade to update to this version.

Removed MapController().onReady

Plugin Migration

Unfortunately, migrating plugins that implement custom layers is more difficult than just renaming in many cases. In good news, the new system requires no complex registration, and will simplify your code.

Previously, state was updated through a StreamBuilder. Since v3, state is updated using setState. This means your tile layer is now just a widget, for all intents and purposes, and anything you put in build will automatically be rebuilt when the map state changes.

To migrate, place any StreamBuilder implementation with the below code snippet, and the latest map state will automatically get passed down.

Your plugin may also now be able to be a StatelessWidget, which may increase performance and simplify your code!

In addition to that change:

Replaced MapState with FlutterMapState

The MapState class has been removed without deprecation.

To migrate, replace MapState with FlutterMapState. This is a name change due to internal reorganization of state management.

Replaced getPixelOrigin with pixelOrigin inside FlutterMapState

The getPixelOrigin method has been removed without deprecation.

To migrate, replace getPixelOrigin with pixelOrigin. This is a name change aimed to improve internal consistency.

You should also credit your tile server if it says to in the server's terms of service. You if using its tile server or another tile server that relies on its data.

However, some useful methods can be found in libraries such as 'latlong2' and . These can be applied to the input of Polygon's points argument, and the map will do it's best to try to render them. However, more complex polygons - such as those with holes - may be painted inaccurately, and may therefore require manual adjustment (of holePointsList, for example).

There are other changes, which can be seen in the full .

For a full list of changes, please see the full , and make use of the old and new API reference.

Removed layers in favour of children

The layers (and nonRotatedLayers) properties on the FlutterMap widget have been removed without deprecation.

To migrate, replace layers with children, and also see .

Removed LayerWidgets & LayerOptions in favour of Layers

All existing LayerWidgets & LayerOptions have been removed without deprecation.

To migrate, replace LayerOptions with Layer. Additionally, if you are currently using children, remove all LayerWidget wrappers.

Replaced onMapCreated with onMapReady inside MapOptions

The onMapCreated property inside the MapOptions object has been removed without deprecation.

To migrate, replace onMapCreated with onMapReady. Note that the current MapController is no longer passed into the callback.

This method should only be used in particular circumstances, and avoided otherwise. See .

See . If this was necessary to await in your project (particularly in initState), you will need to migrate to using .

For more information, see .

must credit OpenStreetMap
'poly_bool_dart'
CHANGELOG
Old Code (<3.0.0)
    layers: [
        TileLayerOptions(),
        MarkerLayerOptions(),
    ],
    children: [
        TileLayerWidget(options: TileLayerOptions()),
        MarkerLayerWidget(options: MarkerLayerOptions()),
    ],
New Code (3.0.0+)
    children: [
        TileLayer(),
        MarkerLayer(),
    ],
@override
Widget build(BuildContext context) {
    final mapState = FlutterMapState.maybeOf(context)!;
    // Use `mapState` as necessary, for example `mapState.zoom`
}
Creating New Layers
Old Code (<3.0.0)
    layers: [],
    nonRotatedLayers: [],
New Code (3.0.0+)
    children: [],
    nonRotatedChildren: [],
Removed LayerWidgets & LayerOptions in favour of Layers
When Map Ready (onMapReady)
Replaced onMapCreated with onMapReady inside MapOptions
When Map Ready (onMapReady)

Older Versions

If you need to update an older project, you may sequentially need to follow migration instructions to get to the latest version.

For this reason, old migrations instructions are kept as subpages beneath this page.

To v1.0.0

This documentation was partially written during this update's lifetime.

Some breaking changes were implemented. Notably:

  • placeholderImage was deprecated with no replacement or workaround. Remove it from your code before the next major release.

  • Some streams were changed from Stream<Null> to Stream<void>. These changes are simple to reflect in your code should you need to.

Creating New Tile Providers

One common requirement is a custom TileProvider, and potentially a custom ImageProvider inside. This will allow your plugin to intercept all tile requests made by a map, and take your own action(s), before finally returning a tile.

Some useful steps are below, but there are more properties of a TileProvider that can be overridden.

Extending The Base TileProvider

To create your own usable TileProvider, the first step is making a class that extends the abstract class. It is not recommended to implement the base, as this will require overriding methods unnecessarily for most custom providers.

class CustomTileProvider extends TileProvider {
    // Add your own custom properties, methods, etc.
    CustomTileProvider({
        // Suitably initialise your own custom properties
        super.headers, // Use the Dart 2.17 `super` syntax to initialise the base's header `Map`
    })
}

Overriding getImage

The majority of custom TileProviders will want to implement their own method to retrieve tiles. This is done by overriding the getImage method, and usually specifying your own ImageProvider, for example:

    @override
    ImageProvider getImage(Coords<num> coords, TileLayerOptions options) =>
        CustomImageProvider(
            options: options,
            coords: coords,
            headers: {
                ...headers,
                'User-Agent': headers['User-Agent'] == null
                    ? '<pluginName> for flutter_map (unknown)'
                    : '<pluginName> for ${headers['User-Agent']}',
            },
        );

Notice that the 'User-Agent' header has been changed. This is recommended, as it helps further differentiate your plugin's traffic from vanilla 'flutter_map' traffic.

Overriding getTileUrl

Some custom TileProviders may want to change the way URLs for tiles are generated. Note that this is quite advanced usage.

    @override
    String getTileUrl(Coords coords, TileLayerOptions options) {
        // Custom generation
    }

Credits

Thanks to everyone who has contributed to flutter_map in anyway, you've helped make it the most popular non-commercially owned mapping solution for Flutter. As well as those that have contributed directly to the code, this includes everyone on the Discord server, everyone who's following the progress, and everyone that's participating in discussions and issues.

If you want to contribute to the codebase, please visit the Contributing instructions. We'd love to have your input!

In particular, thanks go to:

  • John P Ryan - the founder of this project

  • All the current maintainers:

    • @ibrierley

    • @JaffaKetchup

    • @mootw (previously @MooNag)

    • @TesteurManiak

  • All the previous maintainers:

    • @kengu

    • @maRci002

  • The original authors of this documentation:

    • @JaffaKetchup

    • @themisir

    • @comatory

  • Anyone who has made plugins for flutter_map, see the Plugins List

To v0.15.0

This documentation was written during this update's lifetime, and therefore there is no migration information available for upgrading from any previous versions.

CHANGELOG

Using Stadia Maps

'flutter_map' is in no way associated or related with Stadia Maps.

Stadia Maps is a popular tiered-payment (with free-tier) tile provider solution, especially for generic mapping applications. Setup with 'flutter_map' is relatively straightforward, but this page provides an example anyway.

Pre-made Styles

For normal usage with raster tiles, use the Raster URL for the style you like, then follow the Normal (raster) instructions.

For more information about using the vector tiles, see Vector Usage.

Custom Styles

Usage

Normal (raster)

You should remove the 'api_key' (found at the end of the URL) from the URL for readability. Instead, pass it to additionalOptions.

FlutterMap(
    options: MapOptions(
      center: LatLng(51.5, -0.09),
      zoom: 13.0,
    ),
    nonRotatedChildren: [
        AttributionWidget.defaultWidget(
            source: 'Stadia Maps © OpenMapTiles © OpenStreetMap contributors',
            onSourceTapped: () async {
                // Requires 'url_launcher'
                if (!await launchUrl(Uri.parse("https://stadiamaps.com/attribution"))) {
                    if (kDebugMode) print('Could not launch URL');
                }
            },
        )
    ],
    children: [
      TileLayer(
        urlTemplate: "https://tiles.stadiamaps.com/tiles/alidade_smooth_dark/{z}/{x}/{y}{r}.png?api_key={api_key}",
        additionalOptions: {
            "api_key": "<API-KEY>",
        },
        userAgentPackageName: 'com.example.app',
        maxNativeZoom: 20,
      ),
    ],
);

Vector Usage

Stadia Maps' also provides vector tiles. For more information about using vector tiles, please see Using Vector Tiles.

However, please note that this method of integration is still experimental. Many of the Stadia Maps styles utilize advanced features of the Mapbox GL JSON style language which are not yet well-supported.

Other Options

Other servers

There are plenty of other tile servers you can choose from, free or paid. Most provide a static tile service/API, usually called Static Tiles or just Tile Requests (if no vector tiles are supported).

A good catalogue of servers (usually called Providers elsewhere) can be found at the websites below:

Google Maps does not document a static raster tile server. Therefore, flutter_map is unable to show Google Maps.

There is an undocumented endpoint available, however it violates the Google Maps Platform ToS.

Serving your own tiles

Switch2OSM also provides detailed instructions on how to serve your own tiles: this can be surprisingly economical and enjoyable if you don't mind a few hours in a Linux console.

However, this will require a very high-spec computer, especially for larger areas, and hosting this might be more complicated than it's worth. It's very difficult to fully understand the technologies involved.

Contributing

Therefore, your contribution would be greatly appreciated, so we've written a guide to help you contribute successfully.

Contribution Guide

Do you think your contribution is essential to 'flutter_map'/useful to all users?

If not, then creating a plugin might be a good idea. To do this, see the Plugins section in these docs: there is advice, starting templates and a few rules to bear in mind. Plugins are preferred when possible as they keep the base library lightweight and easy to understand.

If you think it might be, continue onwards.

Is the contribution to fix a bug? Do you feel comfortable coding it yourself?

If it is, and you are comfortable fixing it yourself, feel free to create an issue stating the bug, mentioning that you're working on fixing it. Then cleanly fork the main repository, and fix the bug. Make sure you only fix/add/remove what's necessary, as this helps to avoid breaking changes. If there is a quick and dirty fix, try not to use it unless the bug is a big one and might take time to fix otherwise.

If it isn't, open a discussion or an issue stating your request. It might be that other people have already found a way to do it. If people like the idea, and you are comfortable doing it yourself, cleanly fork the main repository. Instead of then working on the main branch, work in a new branch: this helps to avoid merge conflicts until the end of development. You may choose to then open a DRAFT pull request to signify that you are working on it. Make sure you only fix/add/remove what's necessary, as this helps to keep track of changes.

If you don't feel comfortable coding changes yourself, start a discussion or an issue.

I've finished coding it. What's next?

Make sure you thoroughly test your changes, and consider writing automated tests.

Then consider whether you need to write documentation. If you do, make sure you follow a similar format to all the other pages in these docs, and use correct spelling and grammar (consider getting a spell checker for Markdown). Then remember to change the documentation version at 'introduction/go'. Change the title of the grey box, the text version, and the link (to the newest migration page), but leave the dynamic badge and other text untouched. If no new documentation is needed, don't touch the grey box.

After that, check if you need to add a migration guide. This is only applicable if the change was a breaking change.

One last thing! Consider if you need to write examples for your changes. If it's a bug fix, you probably won't need to, unless an example also needs to be fixed. But if it's a feature addition, it needs an example, or at least the updating of an existing example. Make sure you test the example as well!

Can I publish it yet?

Yes! Open a PR (or take the existing PR out of draft stage), and link the issue that you opened.

Hopefully a maintainer will merge your changes quickly. Note that not every new merge will result in a new pub.dev release, so you may have to switch to using the GitHub installation method for your new features.

We appreciate your changes!

Stadia Maps' home page: Stadia Maps' pricing page: Stadia Maps' documentation page:

Stadia Maps offers a variety of out of the box, that don't require customization.

You can find details on Stadia Maps' support for custom styles at the bottom of the .

If you are interested in contributing to this, please join the .

'flutter_map' is only as big and useful as it is because of contributors. You can see a , and there are currently , each potentially from a new contributor.

stadiamaps.com
stadiamaps.com/pricing
docs.stadiamaps.com
map styles
map styles documentation
Discord server
list of current contributors here
GitHub PRs

To v1.1.0

There are other bug fixes, but no other breaking changes associated with this release.

The old method of adding attribution through attributionBuilder on a TileLayer has been deprecated. You should now use , as this fixes issues with the old implementation.

AttributionWidget
LogoRaster tile providers - OpenStreetMap Wiki
LogoProvidersSwitch2OSM
LogoServing TilesSwitch2OSM
LogoIs FMTC Right For Me?FMTC Docs
LogoMapController class - flutter_map library - Dart API
Full API Reference
Logoflutter_map - Thunderforest
Visit our documentation over on Thunderforest's site