Last active
November 15, 2023 01:48
-
-
Save luo3house/791cc7c9a655cc1d635aac06c904773d to your computer and use it in GitHub Desktop.
Flutter: Gesture recognizer hanldes multiple taps, then draggable, useful for map dragging, image scaling (with example)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class MultiTapsToPanGestureRecognizer extends TapAndPanGestureRecognizer { | |
var minTapsToDrag = 1; | |
var timeoutToTaps = const Duration(milliseconds: 200); | |
@protected | |
var canDrag = false; | |
@protected | |
var firedDrag = false; | |
@protected | |
var firstTapms = 0; | |
@protected | |
var tapsBeforeTimeout = 0; | |
@protected | |
reset() { | |
firstTapms = 0; | |
tapsBeforeTimeout = 0; | |
canDrag = false; | |
firedDrag = false; | |
} | |
@override | |
void acceptGesture(int pointer) { | |
super.acceptGesture(pointer); | |
if (currentDown != null) { | |
final nowms = DateTime.now().millisecondsSinceEpoch; | |
final firstTapms = this.firstTapms; | |
if (nowms - firstTapms > timeoutToTaps.inMilliseconds) { | |
reset(); | |
this.firstTapms = nowms; | |
tapsBeforeTimeout = 1; | |
} else { | |
tapsBeforeTimeout++; | |
} | |
} | |
if (tapsBeforeTimeout >= minTapsToDrag) { | |
tapsBeforeTimeout = 0; | |
firstTapms = 0; | |
canDrag = true; | |
} | |
if (currentUp != null && firedDrag) { | |
reset(); | |
} | |
} | |
@override | |
void handleEvent(PointerEvent event) { | |
if (event is PointerMoveEvent) { | |
if (canDrag) { | |
firedDrag = true; | |
super.handleEvent(event); | |
} | |
} else { | |
super.handleEvent(event); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// tap at least 2 times in 500ms, then drag | |
/// fires: | |
/// - on tap down in 2 times | |
/// - on drag start | |
/// - on drag update | |
Widget example() { | |
return RawGestureDetector( | |
behavior: HitTestBehavior.opaque, | |
gestures: { | |
MultiTapsToPanGestureRecognizer: GestureRecognizerFactoryWithHandlers<MultiTapsToPanGestureRecognizer>( | |
() => MultiTapsToPanGestureRecognizer(), | |
(recognizer) { | |
// configure handlers with | |
recognizer | |
// no slop | |
..gestureSettings = const DeviceGestureSettings(touchSlop: 0) | |
// tap at least 2 times, then draggable | |
..minTapsToDrag = 2 | |
..onTapDown = (e) {} | |
..onDragUpdate = (e) {} | |
..onDragEnd = (e) {} | |
..onCancel = () {} | |
} | |
), | |
} | |
); | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment