Layer Interactivity
The following layers are interactable - they have specialised hitTest
ers and support external hit detection:
These all follow roughly the same pattern to setup hit detection/interactivity, and there's three or four easy steps to setting it up.
1. Attach A Hit Notifier
Pass a LayerHitNotifier
to the hitNotifier
parameter of the layer. The LayerHitNotifier
should be created as a ValueNotifier
defaulting to null
, but strongly typed to LayerHitNotifier
.
This notifier will be notified whenever a hit test occurs on the layer, with a LayerHitResult
when an element (such as a Polyline
or Polygon
) within the layer is hit, and with null
when an element is not hit (but the layer is).
final LayerHitNotifier hitNotifier = ValueNotifier(null);
// Inside the map build...
PolylineLayer( // Or any other supported layer
hitNotifier: hitNotifier,
polylines: [], // Or any other supported elements
);
It is possible to listen to the notifier directly with addListener
, if you want to handle all hit events (including, for example, hover events).
However, most use cases just need to handle particular gestures (such as taps). This can be done with a wrapper widget to 'filter' the events appropriately: 3. Gesture Detection.
2. Add hitValue
To Elements
hitValue
To ElementsTo identify which particular element was hit (which will be useful when handling the hit events in later steps), supported elements have a hitValue
property.
This can be set to any object, but if one layer contains all the same type, type casting can be avoided (if the type is also specified in the LayerHitNotifier
's type argument).
The equality of the element depends on the equality of the hitValue
.
Therefore, any object passed to the hitValue
should have a valid and useful equality method.
Objects such as records do this behind the scenes, and can be a good choice to store small amounts of uncomplicated data alongside the element.
3. Gesture Detection
To only handle certain hits based on the type of gesture the user performed (such as a tap), wrap the layer with a gesture/hit responsive widget, such as GestureDetector
or MouseRegion
.
These widgets are smart enough to delegate whether they detect a hit (and therefore whether they can detect a gesture) to the child - although HitTestBehavior.deferToChild
may be required for some widgets to enable this functionality.
This means the layer can report whether it had any form of hit, and the handler widget can detect whether the gesture performed on it actually triggered a hit on the layer below.
// Inside the map build...
MouseRegion(
hitTestBehavior: HitTestBehavior.deferToChild,
cursor: SystemMouseCursors.click, // Use a special cursor to indicate interactivity
child: GestureDetector(
onTap: () {
// Handle the hit, which in this case is a tap
// For example, see the example in Hit Handling (below)
},
// And/or any other gesture callback
child: PolylineLayer(
hitNotifier: hitNotifier,
// ...
),
),
),
4. Hit Handling
Once a LayerHitResult
object is obtained, through the hit notifier, you can retrieve:
hitValues
: thehitValue
s 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
If all the hitValue
s in a layer are of the same type, and the created hit notifier specifies that type in the type argument, typing is preserved all the way to retrieval.
Because the HitNotifier
is a special type of ValueNotifier
, it can be both listened to (like a Stream
), and its value instantly retrieved (like a normal variable).
Therefore, there are two ways to retrieve a LayerHitResult
(or null
) from the notifier:
Using
.value
to instantly retrieve the value This is usually done within a gesture handler, such asGestureDetector.onTap
, as demonstrated below.Adding a listener (
.addListener
) to retrieve all hit results This is useful where you want to apply some custom/advanced filtering to the values, and is not a typical usecase.
// Inside a gesture detector/handler
final LayerHitResult? hitResult = hitNotifier.value;
if (hitResult == null) return;
// If running frequently (such as on a hover handler), and heavy work or state changes are performed here, store each result so it can be compared to the newest result, then avoid work if they are equal
for (final hitValue in hitResult.hitValues) {}
Last updated
Was this helpful?