Layer Interactivity
The following layers support 'interactivity':
These layers don't provide their own 'gesture' callbacks, such as
onTap
These layers automatically perform with Flutter APIs
This means layers report hit on elements through the standard Flutter hit system, and can therefore be detected & handled externally through standard widgets: see Detecting hits & gestures
For advanced information about how flutter_map hit tests, see Hit Testing Behaviour
This may optionally be combined with flutter_map APIs
This allows individual hit elements to be identified externally, through a mechanism of a notifier and element metadata: see Identifying hit elements
Detecting hits & gestures
You may be used to using widgets such as GestureDetector
or MouseRegion
to detect gestures on other normal widgets. These widgets ask the child to decide whether they were hit, before doing their own logic - e.g. converting the hit to the appropriate callback depending on the gesture.
Because flutter_map's layers are just widgets, they can also be wrapped with other widgets and inserted into the map's children
.
This means you can simply wrap layers with GestureDetector
s (for example) which will execute callbacks when the layer is hit. Layers tell Flutter they were hit only if at least one of their elements (such as a Polygon
) were hit.
Here's an example of how you would detect taps/clicks on polygons, and convert a cursor to a click indicator when hovering over a polygon:
class _InteractivityDemoState extends State<InteractivityDemo> {
Widget build(BuildContext context) {
return FlutterMap(
// ...
children: [
// ...
MouseRegion(
hitTestBehavior: HitTestBehavior.deferToChild,
cursor: SystemMouseCursors.click,
child: GestureDetector(
onTap: () {
// ...
},
child: PolygonLayer(
// ...
),
),
),
],
);
}
);
Identifying hit elements
To identify which elements (such as Polygon
s) were hit, flutter_map APIs are required:
A
LayerHitNotifier
exposes results of hit testsElements may have metadata known as
hitValue
s attached, which identify that specific element - these are then exposed by the hit notifier's events/values.The entire system may be strongly typed through type parameters on various parts, if all the
hitValue
s within a layer share the same type
Attach the hit notifier to a layer
Pass the notifier to the hitNotifier
parameter of supported layers. You'll also need to set the type parameter of the layer.
For example, for the PolygonLayer
:
class _InteractivityDemoState extends State<InteractivityDemo> {
Widget build(BuildContext context) {
return FlutterMap(
// ...
children: [
// ...
PolygonLayer<String>(
hitNotifier: hitNotifier,
polygons: [
// ...
],
),
],
);
}
}
Add hit values to elements
These can be anything useful, and are exposed when their element is hit. Remember to set the element's type parameter.
polygons: [
Polygon<String>(
points: [],
label: "Horse Field",
hitValue: "Horse",
),
Polygon<String>(
points: [],
label: "Hedgehog House",
hitValue: "Hedgehog",
),
// ...
],
Handle hits on elements
Once you have a callback (such as the callback to GestureDetector.onTap
), you can handle individual hit events.
To do this, the notifier exposes events of type LayerHitResult
when the layer is hit. These results can be retrieved through the notifier's value
getter:
final LayerHitResult<String>? result = hitNotifier.value;
The result exposes 3 properties:
hitValues
: the hit values of all elements that were hit, ordered by their corresponding element, first-to-last, visually top-to-bottomcoordinate
: the geographic coordinate of the hit location (which may not lie on any element)point
: the screen point of the hit location
Therefore, it's unnecessary to use MapOptions.on...
in combination with layer interactivity to detect the position of a tap.
Elements without a hit value are not included in hitValues
. Therefore, it may be empty if elements were hit but no hitValue
s were defined.
Example
class _InteractivityDemoState extends State<InteractivityDemo> {
final LayerHitNotifier<String> hitNotifier = ValueNotifier(null);
Widget build(BuildContext context) {
return FlutterMap(
// ...
children: [
// ...
MouseRegion(
hitTestBehavior: HitTestBehavior.deferToChild,
cursor: SystemMouseCursors.click,
child: GestureDetector(
onTap: () {
final LayerHitResult<String>? result = hitNotifier.value;
if (result == null) return;
for (final hitValue in result.hitValues) {
print('Tapped on a $hitValue');
}
print('Eating the grass at ${result.coordinate}');
},
child: PolygonLayer<String>(
hitNotifier: hitNotifier,
polygons: [
Polygon<String>(
points: [], // overlapping coordinates with 2nd
label: "Horse Field",
hitValue: "Horse",
),
Polygon<String>(
points: [], // overlapping coordinates with 1st
label: "Hedgehog House",
hitValue: "Hedgehog",
),
],
),
),
),
],
);
}
);
Last updated
Was this helpful?