Reputation: 9220
How do I create a GestureRecognizer
in Flutter that only responds to two-finger gestures, and passes single-finger gestures on to other widgets in the arena?
In my Flutter app, I have a GoogleMap
widget inside a SingleChildScrollView
. The GoogleMap
widget takes a gestureRecognizers
parameter which I have set to the following, otherwise it is not even possible to interact with the map (the ScrollView gets all the touch events, at least 95% of the time...)
gestureRecognizers: const {
Factory<OneSequenceGestureRecognizer>(
EagerGestureRecognizer.new,
),
},
With this GestureRecognizer
, the Google Maps widget responds to single-finger gestures (pan) and two-finger gestures (zoom/pan). I want the widget to respond only two-finger gestures, because currently dragging with one finger on the map widget interrupts the user's ability to scroll the view up or down. So I want single-finger gestures to go to the ScrollView, and two-finger gestures to go to Google Maps. (The Google Maps web widget requires a two-finger gesture for pan, for the same reason...)
How do I replace EagerGestureRecognizer
with a gesture recognizer that causes Maps to only pan if two fingers are down, otherwise to pass the single-finger gesture through to the scroll view?
Upvotes: 0
Views: 393
Reputation: 1671
Is this the correct way to use this?
Currently, I am using it like this but the working of single finger pan and two finger pan is still the same.
gestureRecognizers: {
Factory<OneSequenceGestureRecognizer>(
() => TwoFingerPanZoomEagerGestureRecognizer(),
),
},
Upvotes: 0
Reputation: 9220
OK, I figured it out. The trick is that you need to use a GestureAreaManager
to hold the first touch point until the second touch point goes down:
class TwoFingerPanZoomEagerGestureRecognizer extends EagerGestureRecognizer {
final _gestureArenaManager = GestureArenaManager();
int? _firstPointer;
int? _secondPointer;
@override
void addAllowedPointer(PointerDownEvent event) {
startTrackingPointer(event.pointer);
if (_firstPointer == null) {
// If 1 touchpoint is down, hold the pointer until the 2nd touchpoint
// is down
_firstPointer = event.pointer;
_gestureArenaManager.hold(event.pointer);
} else if (_secondPointer == null) {
// If 2 touchpoints are down, release the first pointer, and accept
// both touchpoints
_gestureArenaManager.release(_firstPointer!);
resolvePointer(_firstPointer!, GestureDisposition.accepted);
_secondPointer = event.pointer;
resolvePointer(_secondPointer!, GestureDisposition.accepted);
} else {
// If 3rd touchpoint is down, ignore it
resolvePointer(event.pointer, GestureDisposition.rejected);
}
}
@override
void handleEvent(PointerEvent event) {
if (event is PointerUpEvent) {
stopTrackingPointer(event.pointer);
if (_secondPointer == event.pointer) {
// Second pointer was lifted
stopTrackingPointer(_secondPointer!);
_secondPointer = null;
} else if (_firstPointer == event.pointer) {
// First pointer was lifted
stopTrackingPointer(_firstPointer!);
_gestureArenaManager.release(_firstPointer!);
// Move second pointer to first pointer slot
_firstPointer = _secondPointer;
_secondPointer = null;
}
} else {
super.handleEvent(event);
}
}
}
Upvotes: 0