A Dart implementation of Leaflet for Flutter apps.
Add flutter_map to your pubspec:
dependencies:
flutter_map: any # or the latest version on Pub
Ensure the following permission is present in your Android Manifest file, located in <project root>/android/app/src/main/AndroidManifest.xml
:
<uses-permission android:name="android.permission.INTERNET"/>
Configure the map using MapOptions
and layer options:
Widget build(BuildContext context) {
return FlutterMap(
options: MapOptions(
center: LatLng(51.5, -0.09),
zoom: 13.0,
),
layers: [
TileLayerOptions(
urlTemplate: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
subdomains: ['a', 'b', 'c']
),
MarkerLayerOptions(
markers: [
Marker(
width: 80.0,
height: 80.0,
point: LatLng(51.5, -0.09),
builder: (ctx) =>
Container(
child: FlutterLogo(),
),
),
],
),
],
);
}
Alternatively initialize the map by specifying bounds instead of center and zoom.
MapOptions(
bounds: LatLngBounds(LatLng(58.8, 6.1), LatLng(59, 6.2)),
boundsOptions: FitBoundsOptions(padding: EdgeInsets.all(8.0)),
),
Configure the map to use Azure Maps by using the following MapOptions
and layer options:
Widget build(BuildContext context) {
return new FlutterMap(
options: new MapOptions(
center: new LatLng(51.5, -0.09),
zoom: 13.0,
),
layers: [
new TileLayerOptions(
urlTemplate: "https://atlas.microsoft.com/map/tile/png?api-version=1&layer=basic&style=main&tileSize=256&view=Auto&zoom={z}&x={x}&y={y}&subscription-key={subscriptionKey}",
additionalOptions: {
'subscriptionKey': '<YOUR_AZURE_MAPS_SUBSCRIPTON_KEY>'
},
),
new MarkerLayerOptions(
markers: [
new Marker(
width: 80.0,
height: 80.0,
point: new LatLng(51.5, -0.09),
builder: (ctx) =>
new Container(
child: new FlutterLogo(),
),
),
],
),
],
);
}
To use Azure Maps you will need to setup an account and get a subscription key
Configure the map to use Open Street Map by using the following MapOptions
and layer options:
Widget build(BuildContext context) {
return new FlutterMap(
options: new MapOptions(
center: new LatLng(51.5, -0.09),
zoom: 13.0,
),
layers: [
new TileLayerOptions(
urlTemplate: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
subdomains: ['a', 'b', 'c']
),
new MarkerLayerOptions(
markers: [
new Marker(
width: 80.0,
height: 80.0,
point: new LatLng(51.5, -0.09),
builder: (ctx) =>
new Container(
child: new FlutterLogo(),
),
),
],
),
],
);
}
Use the new way to create layers (compatible with previous version)
Widget build(BuildContext context) {
return FlutterMap(
options: MapOptions(
center: LatLng(51.5, -0.09),
zoom: 13.0,
),
layers: [
MarkerLayerOptions(
markers: [
Marker(
width: 80.0,
height: 80.0,
point: LatLng(51.5, -0.09),
builder: (ctx) =>
Container(
child: FlutterLogo(),
),
),
],
),
],
children: <Widget>[
TileLayerWidget(options: TileLayerOptions(
urlTemplate: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
subdomains: ['a', 'b', 'c']
)),
MarkerLayerWidget(options: MarkerLayerOptions(
markers: [
Marker(
width: 80.0,
height: 80.0,
point: LatLng(51.5, -0.09),
builder: (ctx) =>
Container(
child: FlutterLogo(),
),
),
],
)),
],
);
}
By default flutter_map supports only WGS84 (EPSG:4326) and Google Mercator (EPSG:3857) projections. With the integration of proj4dart any coordinate reference systems (CRS) can be defined and used.
Define custom CRS:
var resolutions = <double>[32768, 16384, 8192, 4096, 2048, 1024, 512, 256, 128];
var maxZoom = (resolutions.length - 1).toDouble();
var epsg3413CRS = Proj4Crs.fromFactory(
code: 'EPSG:3413',
proj4Projection:
proj4.Projection.add('EPSG:3413', '+proj=stere +lat_0=90 +lat_ts=70 +lon_0=-45 +k=1 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs'),
resolutions: resolutions,
);
Use Custom CRS in map and in WMS layers:
child: FlutterMap(
options: MapOptions(
// Set the map's CRS
crs: epsg3413CRS,
center: LatLng(65.05166470332148, -19.171744826394896),
maxZoom: maxZoom,
),
layers: [
TileLayerOptions(
wmsOptions: WMSTileLayerOptions(
// Set the WMS layer's CRS too
crs: epsg3413CRS,
baseUrl: 'https://www.gebco.net/data_and_products/gebco_web_services/north_polar_view_wms/mapserv?',
layers: ['gebco_north_polar_view'],
),
),
],
);
For more details visit Custom CRS demo page.
- Using Flutter's NetworkImage: Flutter has a built in ImageProvider (NetworkImage) that caches images in memory until an app restart.
class CachedTileProvider extends TileProvider {
const CachedTileProvider();
@override
ImageProvider getImage(Coords<num> coords, TileLayerOptions options) {
return NetworkImage(getTileUrl(coords, options));
}
}
- Using the
cached_network_image
dependency: This dependency has an ImageProvider that caches to disk which means the cache persists through an app restart.
import 'package:cached_network_image/cached_network_image.dart';
class CachedTileProvider extends TileProvider {
const CachedTileProvider();
@override
ImageProvider getImage(Coords<num> coords, TileLayerOptions options) {
return CachedNetworkImageProvider(
getTileUrl(coords, options),
//Now you can set options that determine how the image gets cached via whichever plugin you use.
);
}
}
Lastly we need to add the CachedTileProvider TileProvider to TileLayerOptions
TileLayerOptions(
urlTemplate: 'https://example.com/{x}/{y}/{z}',
tileProvider: const CachedTileProvider()
)
See the example/
folder for a working example app.
To run it, in a terminal cd into the folder.
Then execute ulimit -S -n 2048
(ref).
Then execute flutter run
with a running emulator.
Follow this guide to grab offline tiles
Once you have your map exported to .mbtiles
, you can use mbtilesToPng to unpack into /{z}/{x}/{y}.png
.
Move this to Assets folder and add asset directories to pubspec.yaml
. Minimum required fields for offline maps are:
Widget build(ctx) {
return FlutterMap(
options: MapOptions(
center: LatLng(56.704173, 11.543808),
zoom: 13.0,
swPanBoundary: LatLng(56.6877, 11.5089),
nePanBoundary: LatLng(56.7378, 11.6644),
),
layers: [
TileLayerOptions(
tileProvider: AssetTileProvider(),
urlTemplate: "assets/offlineMap/{z}/{x}/{y}.png",
),
],
);
}
Make sure PanBoundaries are within offline map boundary to stop missing asset errors.
See the flutter_map_example/
folder for a working example.
Note that there is also FileTileProvider()
, which you can use to load tiles from the filesystem.
- flutter_map_marker_cluster: Provides Beautiful Animated Marker Clustering functionality
- user_location: A plugin to handle and plot the current user location in FlutterMap
- flutter_map_location: A plugin to request and display the users location and heading on the map
- flutter_map_location_marker: A simple and powerful plugin display the users location and heading
- flutter_map_tappable_polyline: A plugin to add
onTap
callback toPolyline
- lat_lon_grid_plugin: Adds a latitude / longitude grid as plugin to the FlutterMap
- flutter_map_marker_popup: A plugin to show customisable popups for markers.
- map_elevation: A widget to display elevation of a track (polyline) like Leaflet.Elevation
- flutter_map_floating_marker_titles: Displaying floating marker titles on the map view
For the latest roadmap, please see the Issue Tracker