-
-
Save dipendra-sharma/0d5182638a0a083419b7158950ed4f49 to your computer and use it in GitHub Desktop.
Advanced multi touch gesture detection in flutter
This file contains hidden or 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
import 'package:flutter/gestures.dart'; | |
import 'package:flutter/material.dart'; | |
import 'multi_drag_gestures.dart'; | |
typedef GestureMultiDragUpdateCallback = void Function( | |
Offset initialPosition, Offset latestPosition, double delta); | |
typedef GestureMultiDragEndCallback = void Function( | |
Offset initialPosition, Offset latestPosition, double delta); | |
typedef GestureMultiDragCancelCallback = void Function(); | |
/// This is an advanced version of normal Gesture detector. | |
/// | |
/// This detector includes MultiDrag Gestures along with most of the | |
/// normal gestures supported by [GestureDetector] widget. | |
/// | |
/// Author Harshvardhan Joshi | |
class CustomGestureDetector extends StatefulWidget { | |
/// The widget which needs to access the gestures | |
final Widget child; | |
/// This is the number of pointers which is required to | |
/// at least consider a gesture | |
/// | |
/// It can range from minimum 1 to max pointers supported by the [MultiDragGestureRecognizer] | |
/// | |
/// If the value is set to 2, then the the gesture recognizer | |
/// will handle simple touch gestures (requiring only one pointer) and | |
/// multi touch gestures (requiring more than one pointers). | |
/// | |
final int supportedPointerCount; | |
/// A [HitTestBehavior] value is used to define how the user's touch | |
/// event should be handled on detection. | |
final HitTestBehavior behaviour; | |
/// A [DragStartBehavior] value is used to define if the initial value | |
/// of a drag gesture will be user's first touch or the position when drag | |
/// event actually starts/detected. | |
final DragStartBehavior dragStartBehavior; | |
/// A callback for simple horizontal drag start gesture | |
final GestureDragStartCallback onHorizontalDragStart; | |
/// A callback for simple horizontal drag update gesture | |
final GestureDragUpdateCallback onHorizontalDragUpdate; | |
/// A callback for simple horizontal drag end gesture | |
final GestureDragEndCallback onHorizontalDragEnd; | |
/// A callback for simple horizontal drag cancel gesture | |
final GestureDragCancelCallback onHorizontalDragCancel; | |
/// A callback for simple vertical drag start gesture | |
final GestureDragStartCallback onVerticalDragStart; | |
/// A callback for simple vertical drag update gesture | |
final GestureDragUpdateCallback onVerticalDragUpdate; | |
/// A callback for simple vertical drag end gesture | |
final GestureDragEndCallback onVerticalDragEnd; | |
/// A callback for simple vertical drag cancel gesture | |
final GestureDragCancelCallback onVerticalDragCancel; | |
/// A callback for multi touch horizontal drag start gesture | |
final GestureMultiDragStartCallback onMultiHorizontalDragStart; | |
/// A callback for multi touch horizontal drag update gesture | |
final GestureMultiDragUpdateCallback onMultiHorizontalDragUpdate; | |
/// A callback for multi touch horizontal drag end gesture | |
final GestureMultiDragEndCallback onMultiHorizontalDragEnd; | |
/// A callback for multi touch horizontal drag cancel gesture | |
final GestureMultiDragCancelCallback onMultiHorizontalDragCancel; | |
/// A callback for multi touch vertical drag start gesture | |
final GestureMultiDragStartCallback onMultiVerticalDragStart; | |
/// A callback for multi touch vertical drag update gesture | |
final GestureMultiDragUpdateCallback onMultiVerticalDragUpdate; | |
/// A callback for multi touch vertical drag end gesture | |
final GestureMultiDragEndCallback onMultiVerticalDragEnd; | |
/// A callback for multi touch vertical drag cancel gesture | |
final GestureMultiDragCancelCallback onMultiVerticalDragCancel; | |
/// A callback for simple PAN start gesture | |
final GestureDragStartCallback onPanStart; | |
/// A callback for simple PAN update gesture | |
final GestureDragUpdateCallback onPanUpdate; | |
/// A callback for simple PAN end gesture | |
final GestureDragEndCallback onPanEnd; | |
/// A callback for simple PAN cancel gesture | |
final GestureDragCancelCallback onPanCancel; | |
/// A callback for simple scale start gesture | |
final GestureScaleStartCallback onScaleStart; | |
/// A callback for simple scale update gesture | |
final GestureScaleUpdateCallback onScaleUpdate; | |
/// A callback for simple scale end gesture | |
final GestureScaleEndCallback onScaleEnd; | |
/// A callback for a double tap gesture | |
final GestureTapCallback onDoubleTap; | |
/// A callback for a long press gesture | |
final GestureLongPressCallback onLongPress; | |
/// Public constructor | |
const CustomGestureDetector({ | |
Key key, | |
this.supportedPointerCount = 1, | |
this.child, | |
this.behaviour, | |
this.onDoubleTap, | |
this.onLongPress, | |
this.onMultiHorizontalDragStart, | |
this.onMultiHorizontalDragUpdate, | |
this.onMultiHorizontalDragEnd, | |
this.onHorizontalDragStart, | |
this.onHorizontalDragUpdate, | |
this.onHorizontalDragEnd, | |
this.onHorizontalDragCancel, | |
this.onVerticalDragStart, | |
this.onVerticalDragUpdate, | |
this.onVerticalDragEnd, | |
this.onVerticalDragCancel, | |
this.onMultiHorizontalDragCancel, | |
this.onMultiVerticalDragStart, | |
this.onMultiVerticalDragUpdate, | |
this.onMultiVerticalDragEnd, | |
this.onMultiVerticalDragCancel, | |
this.onPanStart, | |
this.onPanUpdate, | |
this.onPanEnd, | |
this.onPanCancel, | |
this.onScaleStart, | |
this.onScaleUpdate, | |
this.onScaleEnd, | |
this.dragStartBehavior = DragStartBehavior.start, | |
}) : assert(child != null), | |
assert(supportedPointerCount != null && supportedPointerCount > 0), | |
super(key: key); | |
@override | |
_CustomGestureDetectorState createState() => _CustomGestureDetectorState(); | |
} | |
class _CustomGestureDetectorState extends State<CustomGestureDetector> { | |
int get supportedPointerCount => widget.supportedPointerCount; | |
@override | |
void initState() { | |
super.initState(); | |
} | |
@override | |
Widget build(BuildContext context) { | |
final Map<Type, GestureRecognizerFactory> _gestures = | |
<Type, GestureRecognizerFactory>{}; | |
_addDoubleTapGesture(_gestures, widget.onDoubleTap); | |
_addLongPressGesture(_gestures, widget.onLongPress); | |
_addPanGesture( | |
_gestures, | |
widget.onPanStart, | |
widget.onPanUpdate, | |
widget.onPanEnd, | |
widget.onPanCancel, | |
widget.dragStartBehavior, | |
); | |
_addScaleGesture(_gestures, widget.onScaleStart, widget.onScaleUpdate, | |
widget.onScaleEnd, widget.dragStartBehavior); | |
if (supportedPointerCount > 1) { | |
_addMultiHorizontalDragGesture( | |
_gestures, | |
widget.onMultiHorizontalDragStart, | |
widget.onMultiHorizontalDragUpdate, | |
widget.onMultiHorizontalDragEnd, | |
widget.onMultiHorizontalDragCancel, | |
widget.onHorizontalDragStart, | |
widget.onHorizontalDragUpdate, | |
widget.onHorizontalDragEnd, | |
widget.onHorizontalDragCancel, | |
); | |
_addMultiVerticalDragGesture( | |
_gestures, | |
widget.onMultiVerticalDragStart, | |
widget.onMultiVerticalDragUpdate, | |
widget.onMultiVerticalDragEnd, | |
widget.onMultiVerticalDragCancel, | |
widget.onVerticalDragStart, | |
widget.onVerticalDragUpdate, | |
widget.onVerticalDragEnd, | |
widget.onVerticalDragCancel, | |
); | |
} else { | |
_addVerticalDragGesture( | |
_gestures, | |
widget.onVerticalDragStart, | |
widget.onVerticalDragUpdate, | |
widget.onVerticalDragEnd, | |
widget.onVerticalDragCancel, | |
widget.dragStartBehavior, | |
); | |
_addHorizontalDragGesture( | |
_gestures, | |
widget.onHorizontalDragStart, | |
widget.onHorizontalDragUpdate, | |
widget.onHorizontalDragEnd, | |
widget.onHorizontalDragCancel, | |
widget.dragStartBehavior); | |
} | |
return RawGestureDetector( | |
behavior: widget.behaviour, | |
gestures: _gestures, | |
child: widget.child, | |
); | |
} | |
void _addDoubleTapGesture( | |
Map<Type, GestureRecognizerFactory<GestureRecognizer>> gestures, | |
GestureTapCallback onDoubleTap) { | |
if (onDoubleTap != null) { | |
gestures[DoubleTapGestureRecognizer] = | |
GestureRecognizerFactoryWithHandlers<DoubleTapGestureRecognizer>( | |
() => DoubleTapGestureRecognizer(debugOwner: this), | |
(DoubleTapGestureRecognizer instance) { | |
instance..onDoubleTap = onDoubleTap; | |
}, | |
); | |
} | |
} | |
void _addLongPressGesture( | |
Map<Type, GestureRecognizerFactory<GestureRecognizer>> gestures, | |
GestureLongPressCallback onLongPress) { | |
if (onLongPress != null) { | |
gestures[LongPressGestureRecognizer] = | |
GestureRecognizerFactoryWithHandlers<LongPressGestureRecognizer>( | |
() => LongPressGestureRecognizer(debugOwner: this), | |
(LongPressGestureRecognizer instance) { | |
instance..onLongPress = onLongPress; | |
}, | |
); | |
} | |
} | |
void _addVerticalDragGesture( | |
Map<Type, GestureRecognizerFactory<GestureRecognizer>> gestures, | |
GestureDragStartCallback onVerticalDragStart, | |
GestureDragUpdateCallback onVerticalDragUpdate, | |
GestureDragEndCallback onVerticalDragEnd, | |
GestureDragCancelCallback onVerticalDragCancel, | |
DragStartBehavior dragStartBehavior) { | |
if (onVerticalDragStart != null || | |
onVerticalDragUpdate != null || | |
onVerticalDragEnd != null || | |
onVerticalDragCancel != null) { | |
gestures[VerticalDragGestureRecognizer] = | |
GestureRecognizerFactoryWithHandlers<VerticalDragGestureRecognizer>( | |
() => VerticalDragGestureRecognizer(debugOwner: this), | |
(VerticalDragGestureRecognizer instance) { | |
instance | |
..onStart = onVerticalDragStart | |
..onUpdate = onVerticalDragUpdate | |
..onEnd = onVerticalDragEnd | |
..onCancel = onVerticalDragCancel | |
..dragStartBehavior = dragStartBehavior; | |
}, | |
); | |
} | |
} | |
void _addHorizontalDragGesture( | |
Map<Type, GestureRecognizerFactory<GestureRecognizer>> gestures, | |
GestureDragStartCallback onHorizontalDragStart, | |
GestureDragUpdateCallback onHorizontalDragUpdate, | |
GestureDragEndCallback onHorizontalDragEnd, | |
GestureDragCancelCallback onHorizontalDragCancel, | |
DragStartBehavior dragStartBehavior) { | |
if (onHorizontalDragStart != null || | |
onHorizontalDragUpdate != null || | |
onHorizontalDragEnd != null || | |
onHorizontalDragCancel != null) { | |
gestures[HorizontalDragGestureRecognizer] = | |
GestureRecognizerFactoryWithHandlers<HorizontalDragGestureRecognizer>( | |
() => HorizontalDragGestureRecognizer(debugOwner: this), | |
(HorizontalDragGestureRecognizer instance) { | |
instance | |
..onStart = onHorizontalDragStart | |
..onUpdate = onHorizontalDragUpdate | |
..onEnd = onHorizontalDragEnd | |
..onCancel = onHorizontalDragCancel | |
..dragStartBehavior = dragStartBehavior; | |
}, | |
); | |
} | |
} | |
void _addPanGesture( | |
Map<Type, GestureRecognizerFactory<GestureRecognizer>> gestures, | |
GestureDragStartCallback onPanStart, | |
GestureDragUpdateCallback onPanUpdate, | |
GestureDragEndCallback onPanEnd, | |
GestureDragCancelCallback onPanCancel, | |
DragStartBehavior dragStartBehavior) { | |
if (onPanStart != null || | |
onPanUpdate != null || | |
onPanEnd != null || | |
onPanCancel != null) { | |
gestures[PanGestureRecognizer] = | |
GestureRecognizerFactoryWithHandlers<PanGestureRecognizer>( | |
() => PanGestureRecognizer(debugOwner: this), | |
(PanGestureRecognizer instance) { | |
instance | |
..onStart = onPanStart | |
..onUpdate = onPanUpdate | |
..onEnd = onPanEnd | |
..onCancel = onPanCancel | |
..dragStartBehavior = dragStartBehavior; | |
}, | |
); | |
} | |
} | |
void _addScaleGesture( | |
Map<Type, GestureRecognizerFactory<GestureRecognizer>> gestures, | |
GestureScaleStartCallback onScaleStart, | |
GestureScaleUpdateCallback onScaleUpdate, | |
GestureScaleEndCallback onScaleEnd, | |
DragStartBehavior dragStartBehavior) { | |
if (onScaleStart != null || onScaleUpdate != null || onScaleEnd != null) { | |
gestures[ScaleGestureRecognizer] = | |
GestureRecognizerFactoryWithHandlers<ScaleGestureRecognizer>( | |
() => ScaleGestureRecognizer(debugOwner: this), | |
(ScaleGestureRecognizer instance) { | |
instance | |
..onStart = onScaleStart | |
..onUpdate = onScaleUpdate | |
..onEnd = onScaleEnd; | |
}, | |
); | |
} | |
} | |
void _addMultiHorizontalDragGesture( | |
Map<Type, GestureRecognizerFactory<GestureRecognizer>> gestures, | |
GestureMultiDragStartCallback onMultiHorizontalDragStart, | |
GestureMultiDragUpdateCallback onMultiHorizontalDragUpdate, | |
GestureMultiDragEndCallback onMultiHorizontalDragEnd, | |
GestureMultiDragCancelCallback onMultiHorizontalDragCancel, | |
GestureDragStartCallback onHorizontalDragStart, | |
GestureDragUpdateCallback onHorizontalDragUpdate, | |
GestureDragEndCallback onHorizontalDragEnd, | |
GestureDragCancelCallback onHorizontalDragCancel, | |
) { | |
if (onMultiHorizontalDragStart != null || | |
onMultiHorizontalDragUpdate != null || | |
onHorizontalDragStart != null || | |
onHorizontalDragUpdate != null) { | |
gestures[CustomHorizontalMultiDragRecognizer] = | |
getMultiHorizontalDragGestureRecognizer( | |
this, | |
onMultiHorizontalDragStart: onMultiHorizontalDragStart, | |
onMultiHorizontalDragUpdate: onMultiHorizontalDragUpdate, | |
onMultiHorizontalDragEnd: onMultiHorizontalDragEnd, | |
onMultiHorizontalDragCancel: onMultiHorizontalDragCancel, | |
onHorizontalDragStart: onHorizontalDragStart, | |
onHorizontalDragUpdate: onHorizontalDragUpdate, | |
onHorizontalDragEnd: onHorizontalDragEnd, | |
onHorizontalDragCancel: onHorizontalDragCancel, | |
supportedPointerCount: supportedPointerCount, | |
); | |
} | |
} | |
void _addMultiVerticalDragGesture( | |
Map<Type, GestureRecognizerFactory<GestureRecognizer>> gestures, | |
GestureMultiDragStartCallback onMultiVerticalDragStart, | |
GestureMultiDragUpdateCallback onMultiVerticalDragUpdate, | |
GestureMultiDragEndCallback onMultiVerticalDragEnd, | |
GestureMultiDragCancelCallback onMultiVerticalDragCancel, | |
GestureDragStartCallback onVerticalDragStart, | |
GestureDragUpdateCallback onVerticalDragUpdate, | |
GestureDragEndCallback onVerticalDragEnd, | |
GestureDragCancelCallback onVerticalDragCancel, | |
) { | |
if (onMultiVerticalDragStart != null || | |
onMultiVerticalDragUpdate != null || | |
onVerticalDragStart != null || | |
onVerticalDragEnd != null) { | |
gestures[CustomVerticalMultiDragRecognizer] = | |
getMultiVerticalDragGestureRecognizer( | |
this, | |
supportedPointerCount: supportedPointerCount, | |
onMultiVerticalDragStart: onMultiVerticalDragStart, | |
onMultiVerticalDragUpdate: onMultiVerticalDragUpdate, | |
onMultiVerticalDragEnd: onMultiVerticalDragEnd, | |
onMultiVerticalDragCancel: onMultiVerticalDragCancel, | |
onVerticalDragStart: onVerticalDragStart, | |
onVerticalDragUpdate: onVerticalDragUpdate, | |
onVerticalDragEnd: onVerticalDragEnd, | |
onVerticalDragCancel: onVerticalDragCancel, | |
); | |
} | |
} | |
} |
This file contains hidden or 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
import 'dart:async'; | |
import 'package:flutter/material.dart'; | |
/// This class handles a [delayedProcess] with a given [waitDuration] | |
class DelayedProcessHandler { | |
Timer _waitingTimer; | |
final Duration _defaultDuration = Duration(seconds: 10); | |
/// This holds the process which should be executed after the provided delay | |
Function delayedProcess; | |
/// This value is used as a waiting duration, after this duration the process | |
/// will be executed. | |
Duration waitDuration; | |
///Public Constructor | |
DelayedProcessHandler({@required this.delayedProcess, this.waitDuration}) | |
: assert(delayedProcess != null); | |
/// This method will start the waiting process | |
void startWaiting() { | |
waitDuration ??= _defaultDuration; | |
// to cancel previous waiting task assigned to this handler | |
stopWaiting(); | |
_waitingTimer = Timer(waitDuration, () { | |
// AppLog.debug(LogOwner.hjoshi, | |
// 'DelayedProcessHandler.startWaiting() : triggering process...'); | |
delayedProcess(); | |
}); | |
} | |
/// This method will stop the waiting process | |
void stopWaiting() { | |
_waitingTimer?.cancel(); | |
_waitingTimer = null; | |
} | |
} |
This file contains hidden or 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
import 'package:flutter/gestures.dart'; | |
import 'package:flutter/material.dart'; | |
import 'package:flutter_investar/src/utils/delayed_process_handler.dart'; | |
import 'custom_gesture_detector.dart'; | |
/// Class for recognizing multi touch vertical gestures | |
class CustomVerticalMultiDragRecognizer | |
extends VerticalMultiDragGestureRecognizer { | |
/// Amount of current simultaneous pointers/touches | |
int _pointerCount; | |
/// Amount of minimum required simultaneous pointers/touches | |
final int supportedPointerCount; | |
/// A delayed process handler to execute single touch alternative | |
/// of a gesture if multi touch gesture's minimum was not recognized properly | |
/// within a limited amount of time | |
DelayedProcessHandler _delayedProcessHandler; | |
/// Multi touch vertical drag start | |
final GestureMultiDragStartCallback onMultiVerticalDragStart; | |
/// Multi touch vertical drag update | |
final GestureMultiDragUpdateCallback onMultiVerticalDragUpdate; | |
/// Multi touch vertical drag end | |
final GestureMultiDragEndCallback onMultiVerticalDragEnd; | |
/// Multi touch vertical drag cancel | |
final GestureMultiDragCancelCallback onMultiVerticalDragCancel; | |
/// Single touch vertical drag start | |
final GestureDragStartCallback onVerticalDragStart; | |
/// Single touch vertical drag update | |
final GestureDragUpdateCallback onVerticalDragUpdate; | |
/// Single touch vertical drag end | |
final GestureDragEndCallback onVerticalDragEnd; | |
/// Single touch vertical drag cancel | |
final GestureDragCancelCallback onVerticalDragCancel; | |
/// Public constructor | |
CustomVerticalMultiDragRecognizer( | |
Object debugOwner, | |
this.supportedPointerCount, | |
this.onMultiVerticalDragStart, | |
this.onMultiVerticalDragUpdate, | |
this.onMultiVerticalDragEnd, | |
this.onMultiVerticalDragCancel, | |
this.onVerticalDragStart, | |
this.onVerticalDragUpdate, | |
this.onVerticalDragEnd, | |
this.onVerticalDragCancel) | |
: assert(onMultiVerticalDragStart != null || | |
onMultiVerticalDragUpdate != null), | |
super(debugOwner: debugOwner) { | |
_delayedProcessHandler ??= DelayedProcessHandler( | |
delayedProcess: confirmAdditionalPointers, | |
waitDuration: Duration(milliseconds: 100)); | |
onStart = _handleMultiDragOnStart; | |
} | |
Drag _handleMultiDragOnStart(Offset position) { | |
if (_pointerCount < supportedPointerCount) { | |
_pointerCount++; | |
_delayedProcessHandler.startWaiting(); | |
} | |
return ItemDrag(_onDragUpdate, _onDragEnd, _onCancel); | |
} | |
void _onDragUpdate( | |
Offset initialPosition, | |
Offset latestPosition, | |
double delta, | |
) { | |
if (_pointerCount == 1) { | |
if (onVerticalDragUpdate == null) { | |
return; | |
} | |
onVerticalDragUpdate(DragUpdateDetails( | |
globalPosition: latestPosition, | |
delta: Offset(0.0, delta), | |
primaryDelta: delta)); | |
} else { | |
onMultiVerticalDragUpdate(initialPosition, latestPosition, delta); | |
} | |
} | |
void _onDragEnd( | |
Offset initialPosition, | |
Offset latestPosition, | |
double delta, | |
) { | |
if (_pointerCount == 1) { | |
if (onVerticalDragEnd == null) { | |
return; | |
} | |
onVerticalDragEnd(DragEndDetails( | |
velocity: Velocity( | |
pixelsPerSecond: | |
fromDifference(initialPosition, latestPosition)))); | |
} else { | |
if (onMultiVerticalDragEnd == null) { | |
return; | |
} | |
onMultiVerticalDragEnd(initialPosition, latestPosition, delta); | |
} | |
_pointerCount = 0; | |
} | |
void _onCancel() { | |
if (_pointerCount == 1) { | |
if (onVerticalDragCancel == null) { | |
return; | |
} | |
onVerticalDragCancel(); | |
} else { | |
if (onMultiVerticalDragCancel == null) { | |
return; | |
} | |
onMultiVerticalDragCancel(); | |
} | |
_pointerCount = 0; | |
} | |
/// Method to confirm that the minimum pointer requirements is matched | |
void confirmAdditionalPointers() { | |
if (_pointerCount <= supportedPointerCount) { | |
// do something when minimum pointer requirements is not matched | |
} | |
} | |
} | |
/// Class for recognizing multi touch vertical gestures | |
class CustomHorizontalMultiDragRecognizer | |
extends HorizontalMultiDragGestureRecognizer { | |
/// Amount of current simultaneous pointers/touches | |
int pointerCount = 0; | |
/// Amount of minimum required simultaneous pointers/touches | |
final int supportedPointerCount; | |
/// A delayed process handler to execute single touch alternative | |
/// of a gesture if multi touch gesture's minimum was not recognized properly | |
/// within a limited amount of time | |
DelayedProcessHandler _delayedProcessHandler; | |
/// Multi touch horizontal drag start | |
final GestureMultiDragStartCallback onMultiHorizontalDragStart; | |
/// Multi touch horizontal drag update | |
final GestureMultiDragUpdateCallback onMultiHorizontalDragUpdate; | |
/// Multi touch horizontal drag end | |
final GestureMultiDragEndCallback onMultiHorizontalDragEnd; | |
/// Multi touch horizontal drag cancel | |
final GestureMultiDragCancelCallback onMultiHorizontalDragCancel; | |
/// Single touch horizontal drag start | |
final GestureDragStartCallback onHorizontalDragStart; | |
/// Single touch horizontal drag update | |
final GestureDragUpdateCallback onHorizontalDragUpdate; | |
/// Single touch horizontal drag end | |
final GestureDragEndCallback onHorizontalDragEnd; | |
/// Single touch horizontal drag cancel | |
final GestureDragCancelCallback onHorizontalDragCancel; | |
/// Public constructor | |
CustomHorizontalMultiDragRecognizer( | |
Object debugOwner, | |
this.onMultiHorizontalDragStart, | |
this.onMultiHorizontalDragUpdate, | |
this.onMultiHorizontalDragEnd, | |
this.onMultiHorizontalDragCancel, | |
this.onHorizontalDragStart, | |
this.onHorizontalDragUpdate, | |
this.onHorizontalDragEnd, | |
this.onHorizontalDragCancel, | |
this.supportedPointerCount, | |
) : assert(onMultiHorizontalDragStart != null || | |
onMultiHorizontalDragUpdate != null), | |
super(debugOwner: debugOwner) { | |
_delayedProcessHandler ??= DelayedProcessHandler( | |
delayedProcess: confirmAdditionalPointers, | |
waitDuration: Duration(milliseconds: 100)); | |
onStart = _handleMultiDragOnStart; | |
} | |
Drag _handleMultiDragOnStart(Offset position) { | |
if (pointerCount < supportedPointerCount) { | |
pointerCount++; | |
_delayedProcessHandler.startWaiting(); | |
} | |
return ItemDrag(_onDragUpdate, _onDragEnd, _onCancel); | |
} | |
void _onDragUpdate( | |
Offset initialPosition, | |
Offset latestPosition, | |
double delta, | |
) { | |
if (pointerCount == 1) { | |
if (onHorizontalDragUpdate == null) { | |
return; | |
} | |
onHorizontalDragUpdate(DragUpdateDetails( | |
globalPosition: latestPosition, | |
delta: Offset(delta, 0.0), | |
primaryDelta: delta)); | |
} else { | |
onMultiHorizontalDragUpdate(initialPosition, latestPosition, delta); | |
} | |
} | |
void _onDragEnd( | |
Offset initialPosition, | |
Offset latestPosition, | |
double delta, | |
) { | |
if (pointerCount == 1) { | |
if (onHorizontalDragEnd == null) { | |
return; | |
} | |
onHorizontalDragEnd(DragEndDetails( | |
velocity: Velocity( | |
pixelsPerSecond: | |
fromDifference(initialPosition, latestPosition)))); | |
} else { | |
if (onMultiHorizontalDragEnd == null) { | |
return; | |
} | |
onMultiHorizontalDragEnd(initialPosition, latestPosition, delta); | |
} | |
pointerCount = 0; | |
} | |
void _onCancel() { | |
if (pointerCount == 1) { | |
if (onHorizontalDragCancel == null) { | |
return; | |
} | |
onHorizontalDragCancel(); | |
} else { | |
if (onMultiHorizontalDragCancel == null) { | |
return; | |
} | |
onMultiHorizontalDragCancel(); | |
} | |
pointerCount = 0; | |
} | |
/// Method to confirm that the minimum pointer requirements is matched | |
void confirmAdditionalPointers() { | |
if (pointerCount == supportedPointerCount) { | |
pointerCount = 0; | |
} | |
} | |
} | |
/// This Class is required to detect single or simultaneous multi touch | |
/// events on the surface | |
class ItemDrag extends Drag { | |
Offset _initialPosition; | |
Offset _latestPosition; | |
double _delta = 0; | |
/// A drag update gesture, it can be any of following: | |
/// - vertical multi drag update | |
/// - vertical single drag update | |
/// - horizontal multi drag update | |
/// - horizontal single drag update | |
final GestureMultiDragUpdateCallback onDragUpdate; | |
/// A drag update gesture, it can be any of following: | |
/// - vertical multi drag end | |
/// - vertical single drag end | |
/// - horizontal multi drag end | |
/// - horizontal single drag end | |
final GestureMultiDragEndCallback onDragEnd; | |
/// A drag update gesture, it can be any of following: | |
/// - vertical multi drag cancel | |
/// - vertical single drag cancel | |
/// - horizontal multi drag cancel | |
/// - horizontal single drag cancel | |
final GestureMultiDragCancelCallback onCancel; | |
/// public constructor | |
ItemDrag(this.onDragUpdate, this.onDragEnd, this.onCancel); | |
@override | |
void update(DragUpdateDetails details) { | |
_initialPosition ??= details.globalPosition; | |
_latestPosition = details.globalPosition; | |
// delta = details.delta.dx; | |
_delta = _latestPosition.dx - _initialPosition.dx; | |
onDragUpdate(_initialPosition, _latestPosition, _delta); | |
super.update(details); | |
} | |
@override | |
void cancel() { | |
onCancel(); | |
reset(); | |
super.cancel(); | |
} | |
@override | |
void end(DragEndDetails details) { | |
onDragEnd(_initialPosition, _latestPosition, _delta); | |
reset(); | |
super.end(details); | |
} | |
/// Method to set the gesture data to it's initial state | |
void reset() { | |
_initialPosition = null; | |
_latestPosition = null; | |
_delta = 0; | |
} | |
} | |
/// Method to get a multi horizontal drag gesture | |
GestureRecognizerFactoryWithHandlers<CustomHorizontalMultiDragRecognizer> | |
getMultiHorizontalDragGestureRecognizer( | |
Object debugOwner, { | |
GestureMultiDragStartCallback onMultiHorizontalDragStart, | |
GestureMultiDragUpdateCallback onMultiHorizontalDragUpdate, | |
GestureMultiDragEndCallback onMultiHorizontalDragEnd, | |
GestureMultiDragCancelCallback onMultiHorizontalDragCancel, | |
GestureDragStartCallback onHorizontalDragStart, | |
GestureDragUpdateCallback onHorizontalDragUpdate, | |
GestureDragEndCallback onHorizontalDragEnd, | |
GestureDragCancelCallback onHorizontalDragCancel, | |
int supportedPointerCount, | |
}) { | |
return GestureRecognizerFactoryWithHandlers< | |
CustomHorizontalMultiDragRecognizer>( | |
() => CustomHorizontalMultiDragRecognizer( | |
debugOwner, | |
onMultiHorizontalDragStart, | |
onMultiHorizontalDragUpdate, | |
onMultiHorizontalDragEnd, | |
onMultiHorizontalDragCancel, | |
onHorizontalDragStart, | |
onHorizontalDragUpdate, | |
onHorizontalDragEnd, | |
onHorizontalDragCancel, | |
supportedPointerCount, | |
), | |
(CustomHorizontalMultiDragRecognizer instance) {}, | |
); | |
} | |
/// Method to get a multi vertical drag gesture | |
GestureRecognizerFactoryWithHandlers<CustomVerticalMultiDragRecognizer> | |
getMultiVerticalDragGestureRecognizer( | |
Object debugOwner, { | |
GestureMultiDragStartCallback onMultiVerticalDragStart, | |
GestureMultiDragUpdateCallback onMultiVerticalDragUpdate, | |
GestureMultiDragEndCallback onMultiVerticalDragEnd, | |
GestureMultiDragCancelCallback onMultiVerticalDragCancel, | |
GestureDragStartCallback onVerticalDragStart, | |
GestureDragUpdateCallback onVerticalDragUpdate, | |
GestureDragEndCallback onVerticalDragEnd, | |
GestureDragCancelCallback onVerticalDragCancel, | |
int supportedPointerCount, | |
}) { | |
return GestureRecognizerFactoryWithHandlers< | |
CustomVerticalMultiDragRecognizer>( | |
() => CustomVerticalMultiDragRecognizer( | |
debugOwner, | |
supportedPointerCount, | |
onMultiVerticalDragStart, | |
onMultiVerticalDragUpdate, | |
onMultiVerticalDragEnd, | |
onMultiVerticalDragCancel, | |
onVerticalDragStart, | |
onVerticalDragUpdate, | |
onVerticalDragEnd, | |
onVerticalDragCancel, | |
), | |
(CustomVerticalMultiDragRecognizer instance) {}, | |
); | |
} | |
/// a Method to find Difference in offset based on given [initial] and [latest] | |
/// offset values | |
Offset fromDifference(Offset initial, Offset latest) { | |
return Offset((latest.dx - initial.dx), (latest.dy - initial.dy)); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment