generic_map 0.14.0
generic_map: ^0.14.0 copied to clipboard
A generic maps api supporting Google Maps, Mapbox, OpenStreetMaps and MapLibre
Generic Map #
A simple wrapper around:
- flutter_map
- google_maps_flutter
- mapbox_maps_flutter
- maplibre_gl
This library acts as a wrapper around some of the most popular map providers in Flutter. It provides a unified API over multiple map providers, allowing you to switch between them with minimal changes to your code. This is specifically useful when you want to support multiple platforms and need to switch between map providers based on the platform. Additionally it tries to resolve some of the limitations and shortcomings of the official map providers.
β¨ Features #
- π Unified API: Consistent interface across multiple map providers
- π― Feature Parity: Achieve identical functionality across all map providers
- π¨ Widget Markers: Support for widget markers on google_maps (Beyond official API)
- π Mapbox Markers: Widget marker support for mapbox_maps (Not in official API)
- π Declarative Syntax: Simplified marker, polyline, and polygon management vs native APIs
- πΎ Enhanced Caching: Caching capabilities for flutter_map out of the box (thanks to flutter_map_tile_caching)
- β³ Debouncing Support: Debouncing support for more reliable address resolution & improved performance
- π¬ Animation Support: Smooth animations for flutter_map components
Feature Comparison #
| Feature | flutter_map (OSM, MapBox) | Google Maps | Mapbox OpenGL | MapLibre GL |
|---|---|---|---|---|
| Static Markers | β | β | β | β |
| Interactive Markers | β | β | β | β |
| Polylines | β | β | β | β |
| Circles | β | β | β | β |
| Map Gestures | β | β | β | β |
| Heatmaps | β | β | β | β |
| Geofencing | β | β | β | β |
| Caching | β | β | β | β |
| Animations | β | β | β | β |
Platform Support #
Some map providers do not support all platforms. Through PlatformMapProviderSettings you can specify which map provider to use on each platform.
| Platform | flutter_map (OSM, MapBox) | Google Maps | Mapbox OpenGL | MapLibre GL |
|---|---|---|---|---|
| Android | β | β | β | β |
| iOS | β | β | β | β |
| Web | β | β | β | β |
| Desktop | β | β | β | β |
Installation #
Add this package to your pubspec.yaml as a git dependency:
dependencies:
generic_map:
git:
url: https://github.com/lume-code/generic_map.git
To pin to a specific version, add a ref:
generic_map:
git:
url: https://github.com/lume-code/generic_map.git
ref: v0.11.1 # tag, branch, or commit SHA
This package uses gm_google_maps_flutter (a renamed fork of google_maps_flutter with editable polyline/polygon support on web). No dependency_overrides are needed -- the forked packages are bundled and resolved automatically via path dependencies.
Usage #
import 'package:generic_map/generic_map.dart';
import 'package:latlong2/latlong.dart';
import 'package:flutter/material.dart';
final map = GenericMap(
initialLocation: Place(
LatLng(37.7749, -122.4194), // San Francisco coordinates
"San Francisco",
"CA",
),
platformMapProviderSettings: PlatformMapProviderSettings(
android: MapProviderEnum.googleMaps,
ios: MapProviderEnum.mapbox,
web: MapProviderEnum.mapLibre,
),
mapboxOptions: MapboxOptions(
accessToken: 'YOUR_MAPBOX_ACCESS_TOKEN',
styleUri: 'YOUR_MAPBOX_STYLE_URI',
),
mapLibreOptions: MapLibreOptions(
accessToken: 'YOUR_MAPLIBRE_ACCESS_TOKEN',
styleUri: 'YOUR_MAPLIBRE_STYLE_URI',
),
mode: MapViewMode.static,
interactive: true,
markers: [
CustomMarker(
id: "marker1",
position: LatLng(37.7749, -122.4194),
widget: Container(
padding: EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.5),
spreadRadius: 2,
blurRadius: 5,
offset: Offset(0, 3),
),
],
),
child: Text(
'San Francisco',
style: TextStyle(fontWeight: FontWeight.bold),
),
),
),
],
polylines: [
PolyLineLayer(
id: "route1",
points: [
LatLng(37.7749, -122.4194),
LatLng(37.7952, -122.4028),
],
color: Colors.blue,
width: 3,
),
],
circleMarkers: [
CircleMarker(
id: "circle1",
color: Colors.red.withOpacity(0.5),
borderColor: Colors.red,
borderStrokeWidth: 2,
radius: 30,
point: LatLng(37.7833, -122.4667),
),
],
padding: EdgeInsets.all(20),
onMapMoved: (event) {
print('Map moved to: ${event.latLng} (${event.type}, ${event.source})');
},
addressResolver: (LatLng location) async {
// Implement your address resolving logic here
return Place(location, "Some Address", "Some Title");
},
);
Map movement events #
onMapMoved receives a MapMovedEvent describing two independent things:
typeβ where in the movement the event sits:startwhen the camera begins moving,idleonce it has been still formapMoveDebounce, andaddressResolvedwhen the geocoder answers for that resting position.sourceβ what moved the camera:MapMoveSource.gesturefor the user (drag, fling, pinch, double-tap zoom, scroll wheel),programmaticfor the app's ownMapViewController.moveCamera/fitBounds, andunknownfor a move that is neither β the map settling into its initial camera, a viewport change, or a provider reporting a camera change before it has ever come to rest.
The two are separate because "the map moved" is not "the user panned".
Anything that follows a moving position moves the camera itself, so without
source each follow step reads as the user taking over and cancels the
following that produced it:
onMapMoved: (event) {
if (event.type == MapMoveEventType.start && event.isUserGesture) {
setState(() => following = false); // the user took over β stop following
}
},
event.isUserGesture and event.isProgrammatic are shorthands for comparing
source.
What each provider can tell apart
- Google Maps, Mapbox SDK β both report that the camera moved and nothing
about why, so generic_map reconstructs the cause from the camera calls it
made: a move is
programmaticfrom theMapViewControllercall until the camera next settles, and a gesture otherwise. Two consequences: a move made through the raw platform controller, reaching pastMapViewController, is reported as a gesture; and a camera call that moves nothing β recentring on the position the camera already holds β has no settle to end it, so gestures for the next few seconds are reported asprogrammatic. - flutter_map β reports the cause itself, and generic_map maps it straight
across, so what it does report is exact. It reports less, though: it emits
movement start/end only for drags, two-finger gestures and double-tap zoom.
Scroll-wheel zoom, keyboard panning and
MapControllermoves produce noonMapMovedat all, soprogrammaticevents do not occur on flutter_map β a follow feature has nothing to cancel there, but it also gets noidlefor its own moves.