Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
If you don't know about standard map things, such as the latitude/longitude system and projections, you should probably read about these first!
If you want a truly British insight into this, look no further than: https://youtu.be/3mHC-Pf8-dU & https://youtu.be/jtBV3GgQLg8.
Interactive maps are formed from multiple layers of data, which can be panned (moved), rotated, and sometimes tilted/pitched, based on the user's gesture input, or another programmatic control.
One type of layer included on every map is known as a tile layer, which displays tiles, square segments of a map.
When multiple tiles, which are each the same dimensions, are laid out around each other, they give the illusion of one continuous map.
Tiles can be referenced/identified in a few different ways, such as:
Slippy Map Convention (the most popular/common)
TMS (very similar to the Slippy Map Convention)
Tiles themselves can be of two types:
Raster Each tile is a normal pre-rendered standard image, such as JPG or PNG
Vector Each tile is a special format containing the data for the tile, and is then rendered by the end library
This library/documentation focuses on maps accessible via the Slippy Map Convention, although all are supported.
This library only supports raster tiles. See Raster vs Vector Tiles for more information.
For more information about the Slippy Map Convention, visit the OpenStreetMap Wiki.
Slippy map tiles are accessed by 3 coordinates, x/y/z.
X & Y coordinates correspond to all the latitudes and longitudes contained within that tile, however they are not actual longitude and latitude. For example, geographic coordinate (61.127, -0.123) in the tile (128983, 430239).
The Z value represents the current zoom level, where one tile (0/0/0) covers the entire planet with extremely low detail at level 0, to level 20 (although some tile servers will support even higher zoom levels) where over 1 trillion tiles are required to cover the entire surface of the Earth.
Tiles, especially raster tiles, take a lot of computing power and time to generate, because of the massive scale of all the input and output data. Therefore, most tiles are sourced externally, from an online tile server (either publicly or by users holding an API key), or sometimes from the local filesystem or asset store of the app.
A tile provider (within flutter_map) is responsible for:
Constructing the path/URL to a tile, when given its coordinates (x/y/z): #slippy-map-convention
Using an ImageProvider
or other mechanism to fetch that tile: #sourcing-tiles
Performing any other processing steps, such as caching
But don't worry! flutter_map (or a plugin) creates a provider for you, so for most use cases and tile sources, you shouldn't 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'!
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 Stack
s) instead of a flat-based layout (eg. using Column
s). 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
.
The map will expand as much as possible.
To avoid errors about infinite/unspecified dimensions, ensure the map is contained within a known size widget.
To dictate what the map can/should do, regardless of its contents, it needs some guidance!
It provides options that can be categorized into three main parts:
Initial positioning Defines the location of the map when it is first loaded
Permanent rules Defines restrictions that last throughout the map's lifetime
Event handling Defines methods that are called on specific map events
One part of MapOptions
responsibilities is to define how the map should be positioned when first loaded. There's two ways to do this (that are incompatible):
center
& zoom
Defines the center coordinates of the map and a zoom level
bounds
Defines an area with two/four coordinates that the viewport should fit to
It is possible to also set the map's rotation
in degrees, if you don't want it North (0°) facing initially.
Changing these properties after the map has already been built for the first time will have no effect: they only apply on initialisation.
To control the map programatically, use a MapController
: Controller.
One part of MapOptions
responsibilities is to define the restrictions and limitations of the map and what users can/cannot do with it.
You should check all the available options, but these are recommended for most maps:
maxZoom
(and minZoom
)
Limits how far the map can be zoomed by the user, to avoid showing empty tiles
maxBounds
Limits how far the map can be moved by the user to a coordinate-based boundary
interactiveFlags
- see InteractiveFlag
for available options
Limits what methods the user can interact with the map through (for example, preventing rotation)
keepAlive
If FlutterMap
is located inside a PageView
, ListView
or another complex lazy layout, set this true
to prevent the map from resetting to the #initial-positioning on rebuild
Instead of maxZoom
(or in addition to), consider setting maxNativeZoom
per TileLayer
instead, to allow tiles to scale (and lose quality) on the final zoom level, instead of setting a hard limit.
nonRotatedChildren
Similar to children
, but these don't rotate or move with the other layers.
options
(MapOptions
)
Configure options that don't directly affect the appearance of the map, such as starting location and maximum zoom limit.
mapController
Attach a controller object to control the map programatically, including panning and zooming.
children
Takes a List
of Widgets
(usually a dedicated 'layer') to display on the map, such as tile layers or polygon layers,
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 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 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.
Due to the complications mentioned above, 'flutter_map' does not natively support vector tiles. However, vector tiles can be used with a community maintained plugin (vector_map_tiles
) to do this.
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 v5 only!
Use the version selector in the top left to choose documentation suitable for your version.
Setting up an interactive and map is simpler than making your lunch-time coffee! It can be accomplished in just under 30 lines and a minute or two to install.
This code snippet demonstrates everything you need for a simple map (in just over 20 lines!), but of course, FM is capable of much more than just this, and you could find yourself lost in the many options available and possibilities opened!
Not quite sure about something? No problem. Please get in touch via any of these methods, and we'll be with you as soon as possible. Please remember that we are volunteers, so we cannot guarantee (fast) support.
For bug reports & feature requests: GitHub Issues
For general support & everything else: flutter_map Discord server
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. No more vendor lock-in!
Stress-free setup and use
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 other map features
Add polygons, polylines, and markers/pins to your map easily and quickly. Markers support displaying any widget you might want.
All users should also install 'latlong2' to work with coordinates in 'flutter_map'.
In the event that the LatLng
object provided by that library conflicts with another, for example the one provided by Google Maps, you may need to use the 'as' suffix.
Just import the package as you would normally, from the command line:
Commits available from Git (GitHub) may not be stable. Only use this method if you have no other choice.
If you urgently need the latest version, a specific branch, or a specific fork, you can use this method.
First, use #from-pub.dev, then add the following lines to your pubspec.yaml file, as a root object:
Always force usage of the CanvasKit renderer instead of the HTML renderer, even on mobile devices.
Failure to do so leads to severely impacted performance and some broken features.
For more information about web renderers, see https://docs.flutter.dev/platform-integration/web/renderers.
flutter_map needs to access the Internet to load tiles, in most cases. On Android, apps must include the INTERNET permission in their manifest. Add the following line to all manifests:
flutter_map needs to access the Internet to load tiles, in most cases. On MacOS, apps must include a dedicated entitlement. Add the following lines to 'macos/Runner/DebugProfile.entitlements' and 'macos/Runner/Release.entitlements':
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.
If building a custom layer (Creating New Layers), consider using FlutterMapState
directly instead.
When changes happen to FlutterMap
's internal state, such as a change to the current position or zoom, it emits a MapEvent
, which can be handled by you.
There's two ways to catch all emitted MapEvent
s, and use them/the Stream<MapEvent>
directly.
These methods expose the raw MapEvent
, and is recommended in cases where multiple events need to be caught, or there's no more specific callback method available in MapOptions
.
Listening to a MapController
's mapEventStream
Specifying a callback method in MapOptions.onMapEvent
If only a couple of events need to be caught, such as just an onTap
handler, it is possible to avoid handling the raw Stream
of MapEvent
s. Instead, MapOptions
has callbacks available for the following events:
onTap
onLongPress
onPositionChanged
onPointerDown
/onPointerUp
/onPointerHover
/onPointerCancel
onMapReady
Primarily used for advanced MapController
#usage-in-initstate
The MapEventTap
event may be emitted (or the onTap
callback called) 250ms after the actual tap occurred, as this is the acceptable delay between the two taps in a double tap zoom gesture.
If this causes noticeable jank or a bad experience (for example, on desktop platforms), disable InteractiveFlag
.doubleTapZoom
:
This disables the double tap handler, so the MapEventTap
is emitted 'instantly' on tap.
The tileProvider
parameter in TileLayer
takes a TileProvider
object specifying a tile provider to use for that layer.
This has a default of NetworkTileProvider
which gets tiles from the internet through a dedicated image provider.
There's two situations in which you'll need to change the tile provider:
Sourcing tiles from the filesystem or asset store: #local-tile-providers
Using a plugin that instructs you to do so (Creating New Tile Providers)
NetworkTileProvider
takes two arguments, but you'll usually never need to specify them:
httpClient
: custom BaseClient
By default, a RetryClient
backed by a standard Client
is used
headers
: custom Map<String, String>
By default, only the default headers, plus a custom 'User-Agent' header based on the #useragentpackagename property, are included with each request
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.
Specifying any fallbackUrl
(even if it is not used) in the TileLayer
will reduce the performance of these providers.
It will cause 23% slower asset tile requests with AssetTileProvider
, and will cause main thread blocking when requesting tiles from FileTileProvider
.
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 throw an UnsupportedError
when a tile request is attempted, due to the lack of the web platform's access to the local filesystem.
If you know you are running on the web platform, use a NetworkTileProvider
or a custom tile provider.
flutter_map provides an example application showcasing much of its functionality. In some cases, the example app contains undocumented functionality, so it's definitely worth checking out!
Note that the web demo is built automatically from the 'master' branch, so may not reflect the the latest release on pub.dev.
Please don't abuse the web demo! It runs on limited bandwidth and won't hold up to thousands of loads.
If you're going to be straining the application, please see #prebuilt-artifacts, and serve the application yourself.
If you can't build from source for your platform, our GitHub Actions CI system compiles the example app to GitHub Artifacts for Windows, Web, and Android.
The Windows and Android artifacts just require unzipping and installing the .exe or .apk found inside.
The Web artifact requires unzipping and serving, as it contains more than one unbundled file. You may be able to use dhttpd for this purpose.
Note that these artifacts are built automatically from the 'master' branch, so may not reflect the the latest release on pub.dev.
Note that these artifacts may become unavailable a while, in which case you'll need to build from source.
If you need to use the example app on another platform, you can build from source, using the 'example' directory of the repository.
To display anything on the map, you'll need to include at least one "layer"!
Multiple layers can be used - similar to a Stack
- each one showing different data in different ways, from actual map tiles (Tile Layer) to shapes on top of them (Polygon Layer), and even just your own custom layers (Creating New Layers).
Each layer has its own configuration and handling, but can also access the map's state/configuration, as well as be controlled by it.
Layers are usually defined in the children
property of the FlutterMap
- as is with the TileLayer
, for example.
Gesture handling is handled by the children
in reverse order. The topmost/last layer will absorb (and optionally use) all gestures on the map. Therefore, there can only be one interactive layer.
It is recommended to place the TileLayer
first/bottom, the interactive layer (if any) last/top, and other layers in between.
If the interactive layer is not the topmost layer, you must allow gestures to work their way down to it through all the layers above. To do this, wrap all these layers in IgnorePointer
widgets, to prevent the layer from receiving/absorbing gestures.
Note that this does not apply to the map as a whole. The map will receive raw gestures, and manipulate the children
via the map's state. Thus, individual layers may react to processed gestures from the state - in this way, they do not react to the incoming gestures themselves. This is why placing layers above the TileLayer
does not impact its ability to respond to gestures.
However, the nonRotatedChildren
property can be used for layers which shouldn't move with the map, but still require access to the map's state/configuration - for example, the AttributionLayer
s.
Do not use nonRotatedChildren
to enforce a non-rotatable map/TileLayer
.
Instead, use interactiveFlags
: #permanent-rules. These apply to the entire map and all layers.
This update brings support for Dart 3 and Flutter 3.10.
We've updated some dependencies, including 'latlong2' (to 0.9.0) and 'http' (1.0.0)!
LatLng
objects now have const
constructors to improve performance. To automatically insert the const
keyword where necessary, run dart fix
.
There are a few minor breaking changes for some users, but most changes are internal and need no work to take advantage of.
Please refer to the sections below for information on how to migrate your project. This will contain the changes that most users may need to make, but not all changes. It also excludes some deprecations where the message is self-descriptive.
For a full list of changes, please see the full CHANGELOG, and make use of the old and new API reference.
You can add lines to maps by making them out of individual coordinates using PolylineLayer
and Polyline
s.
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 may create performance issues.
Consider using one of the methods below if you encounter jank:
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.
Routing is out of scope for 'flutter_map'. However, if you can get a list of coordinates from a 3rd party, then you can use polylines to show them!
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.
You can then use the package and the above snippet by doing:
You can add areas/shapes to maps by making them out of individual coordinates using PolygonLayer
and Polygon
s.
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 may create performance issues.
Consider 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.
'flutter_map' doesn't provide any public methods to manipulate polygons, as these would be deemed out of scope.
onTap
There is no support for handling taps on polygons, due to multiple technical challenges. To stay up to date with this existing feature request, see the linked issue.
You can add circle areas to maps by making them out of a center coordinate and radius using CircleLayer
and CircleMarker
s.
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 may create performance issues.
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 .
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.
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:
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).
The basis of any map is a TileLayer
, which displays square raster images in a continuous grid, sourced from the Internet or a local file system.
flutter_map supports WMS Usage, but most map tiles are accessed through the CARTO/XYZ/Slippy Map standard, where the mapping library (flutter_map) fills in XYZ placeholders in a URL.
You must comply to your tile server's ToS. Failure to do so may result in you being banned from their services.
The OpenStreetMap Tile Server (as used above) can be found here. Other servers may have different terms.
This package is not responsible for your misuse of any tile server.
It is possible to use more than one tile layer, and can be used with transparency/opacity.
The children
list works like the children of a Stack
: last is on top.
Need more control over the source of tiles, or how tiles are fetched? You'll need to change the TileProvider
.
userAgentPackageName
Always specify the userAgentPackageName
argument to avoid being blocked by your tile server.
It should be passed the application's package name, such as 'com.example.app'. This is important to avoid blocking by tile servers due to high-levels of unidentified traffic. If no value is passed, it defaults to 'unknown'.
This is passed through to the NetworkTileProvider
(if in use) in a suitably formatted string, where it forms the 'User-Agent' header, overriding any custom user agent specified in the HTTP client.
To override this behaviour, specify a 'User-Agent' key in the NetworkTileProvider
.headers
property.
This is all ignored on the web, where the 'User-Agent' header cannot be changed due to a limitation of Dart/browsers.
To programatically interact with the map (such as panning, zooming and rotating) and receive it's events, you'll need a MapController
.
If building a custom layer (Creating New Layers), consider using FlutterMapState
directly instead.
To use a MapController
, it must initialised like any other object and then passed to the FlutterMap
. This attaches them until the map is disposed.
Avoid disconnecting the map from the controller, as it can cause problems. If you need to change the map's contents:
Change its children
(layers) individually
Re-initialise a new MapController
, and keep it in an external state system
If you still get issues, and FlutterMap
is located inside a PageView
, ListView
or another complex lazy layout, try setting keepAlive
true
in MapOptions
: #permanent-rules.
initState()
It is a fairly common requirement to need to use the MapController
in initState()
, before the map has been built. Unfortunately, this is not possible, as the map must be built for the controller to be attached.
This isn't a problem however! The MapOptions
contains an onMapReady
callback (see #event-handling) is called when the map is initialised, and the initialised map controller can be used freely within it.
It may also be possible to use SchedulerBinding
or WidgetsBinding
in initState
to run a method after the first frame has been built, as detailed here: https://stackoverflow.com/a/64186549/11846040. You'll probably see this approach in many older projects.
That method will, however, not work if the map is not built on the first frame. This may be the case if it is, for example, in a FutureBuilder
.
MapController
methods that change the position of the map should not be used instantly in onMapReady
- see issue #1507.
Using them as a reaction to a map event is still fine.
Whilst animated movements through MapController
s aren't built-in, the community maintained plugin flutter_map_animations
provides this, and much more!
The example application also includes a page demonstrating a custom animated map movement without the plugin.
Before publishing your app to users, you should credit any sources you use, according to their Terms of Service.
There are two built in methods to provide attribution, RichAttributionWidget
and SimpleAttributionWidget
, but you can also build your own using a simple Align
widget. All of these should be inserted into the map's nonRotatedChildren
.
You must comply to your tile server's ToS. Failure to do so may result in you being banned from their services.
The OpenStreetMap Tile Server (as used above) can be found here. Other servers may have different terms.
This package is not responsible for your misuse of another tile server.
Please consider crediting flutter_map. It helps us to gain more awareness, which helps make this project better for everyone!
RichAttributionWidget
An animated, interactive attribution layer that supports both logos/images (displayed permanently) and text (displayed in a popup controlled by an icon button adjacent to the logos).
It is heavily customizable (in both animation and contents), and designed to easily meet the needs of most ToSs out of the box.
For more information about configuration and all the many options this supports, see the in-code API documentation.
SimpleAttributionWidget
We also provide a more 'classic' styled box, similar to those found on many web maps. These are less customizable, but might be preferred over RichAttributionWidget
for maps with limited interactivity.
flutter_map supports WMS tile servers through WMSTileLayerOptions
- wmsOptions
in TileLayer
s.
For usage, please refer to the Full API Reference, and the examples in the example app.
Omit urlTemplate
if using WMS tiles. The template is now specified in the baseUrl
property of WMSTileLayerOptions
.
You can add single point features - such as pins, labels, or markers - to maps using MarkerLayer
and Marker
s.
No more image only markers! Unlike other popular mapping libraries, we allow usage of any widget as the marker.
Excessive use of markers may create performance issues.
Consider using a clustering plugin to merge nearby markers together, reducing the work that needs to be done when rendering: #marker-clustering.
Marker rotation support isn't built in (other than counter rotating to the map, to ensure the marker is always displayed right side up), but can easily be implemented through a rotation widget, such as Transform.rotate
.
You can overlay images on the map (for example, town or floor plans) using OverlayImageLayer
and OverlayImage
s or RotatedOverlayImage
s.
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.
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.
'flutter_map' is in no way associated or related with Thunderforest (or Gravitystorm Limited).
Thunderstorm's home page: thunderforest.com Thunderstorm's pricing page: thunderforest.com/pricing Thunderstorm's documentation page: thunderforest.com/docs/map-tiles-api
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.
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:
Attempting to use the widget above outside of a FlutterMap
widget will result in an error, due to the usage of FlutterMapState.of(context)
.
If creating a hybrid widget for usage outside of a layer, use the maybeOf
method instead.
'flutter_map' is in no way associated or related with Mapbox.
Mapbox's Maps home page: Mapbox's Maps pricing page: Mapbox's Maps documentation:
To integrate with 3rd party mapping libraries, Mapbox provides an alternative to the normal 'Style URL' for each map style (and any custom map styles).
The 'CARTO' 'Integration URL' contains all the information and placeholders that flutter_map requires to display a map. Tiles requested through this endpoint consume the 'Static Tiles API' quota.
Once you have the appropriate URL for your desired map style (see ), use it in a TileLayer
's urlTemplate
as normal.
Retina tiles (high-DPI) tiles are used by default ('@2x'). The maximum zoom level that Mapbox supports is 22, so it is recommended to set maxNativeZoom
or maxZoom
as such.
Attribution is required, see .
Consider using the , which meets the requirements by supporting both logo and text attribution.
Mapbox supports creating and using custom styled maps through Studio. These are compatible with flutter_map.
Once you've found a style that suits your needs, or created your own, make it public, then open the 'Share & develop' modal:
Scroll to the bottom of the modal, and select 'Third party'. Then from the drop down box, select 'CARTO'. Copy the 'Integration URL' to your clipboard, and use as above.
This URL should be used as above, although you may need to insert the placeholders manually.
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.
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.
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:
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.
getTileUrl
Some custom TileProviders
may want to change the way URLs for tiles are generated. Note that this is quite advanced usage.
Mapbox offers a variety of ready-made map styles that don't require customization. An example URL can be found in .
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.
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 groups markers together under bigger markers when zoomed further out, decluttering your UI and giving a performance boost.
Marker
sPolyline
s & Polygon
sflutter_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 Polyline
s and Polygon
s
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 Polyline
s
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
fluttermap_heatmap (tprebs)
Provides a layer to represent multiple data points in a density to color relationship
Using maps without an Internet connection is common requirement. Luckily, there are a few options available to you to implement offline mapping in your app.
Caching Automatically store tiles as the user loads them through interacting with the map
Bulk downloading Download an entire area/region of tiles in one shot, ready for a known no-Internet situation
Bundling Provide a set of tiles to all users through assets or the filesystem
The community maintained plugin 'flutter_map_tile_caching' aims to solve the first two points. FMTC is designed to be easy to implement, but also sufficiently advanced to cover most (if not all) use cases.
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 use case, please see:
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.
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.
If you have a raster-format .mbtiles file, for example from TileMill, you should use mbtilesToPngs to convert it to the correct structure first. Alternatively, you can use an external package such as 'flutter_mbtiles_extractor' to extract during runtime.
'flutter_map' is in no way associated or related with Stadia Maps.
Stadia Maps' home page: stadiamaps.com Stadia Maps' pricing page: stadiamaps.com/pricing Stadia Maps' documentation page: docs.stadiamaps.com
To integrate with 3rd party mapping libraries, Stadia Maps provides an alternative to the normal 'Static Maps Base URL' for each map style.
The 'Raster XYZ PNGs' URL contains all the information and placeholders that flutter_map requires to display a map. Tiles requested through this endpoint consume the 'Styled Raster Map Tiles' credits.
Once you have the appropriate URL for your desired map style (see #styles), use it in a TileLayer
's urlTemplate
as normal.
Retina tiles (high-DPI) tiles are available. Use the URLs containing '@2x' instead of '{r}'. The maximum zoom level that Stadia Maps supports is 20, so it is recommended to set maxNativeZoom
or maxZoom
as such.
Attribution is required, see docs.stadiamaps.com/#legal-details-required-attribution.
Consider using the #richattributionwidget or #simpleattributionwidgets, which meet the requirements.
Stadia Maps offers a variety of ready-made map styles that don't require customization. URLs are found with the style: see the available map styles. The URL should be used as above.
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.
'flutter_map' is only as big and useful as it is because of generous open-source contributors!
We're always happy to receive improvements and fixes, so please submit them whenever you can! A few key points are listed below.
Many feature additions are more suitable for plugins, instead of being added to the core. This is aimed to reduce the future maintenance burden/cost on the maintainers.
If we deny your PR for this reason, please do consider publishing a plugin, and we'll be happy to add it to the ! See for more information.
Create a draft PR as soon as work starts, and take it out of draft status when ready for review
Avoid changing the package version or GitHub workflows
Fix issues reported by the GitHub workflows (such as formatting)
Avoid resolving conflicts yourself, if you're not 100% sure what you're changing
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.
If you're responsible for a tile server, and want to have your tile server and setup instructions listed in this documentation, please get in touch!
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.
Always your PR to at least one issue, and as many as are resolved
Keep PRs to a specific scope where possible General/multi-resolution PRs are also perfectly OK, and by the time we get our hands onto it, it usually expands quite quickly
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
Notable contributors:
@rorystepenson
@ignatz
@josxha
Anyone who has made plugins for flutter_map, see the Plugins List
We get quite a lot of similar questions, so please check if your question is here before you ask!