Reputation: 81
I am creating a drawing canvas with flutter for which I want to use both scale (for zooming, panning and rotating) and Pan (for drawing with fingers) gestures but flutter doesn't allow that since Scale is a superset of Pan. Is there any workaround for this?
I tried to create my own custom gesture recognizer for detecting the number of pointers on the screen so that if two pointers come in contact with the screen within a short interval of time(let's say 1 second) Scale takes over otherwise pan starts working with the 1st pointer that touched the screen. I am using matrix_gesture_detector package for doing the scaling part.
Here is my code for the custom gesture recognizer
class ScaleAndPanRecognizer extends OneSequenceGestureRecognizer {
var manager = GestureArenaManager();
final Function onPanDown;
final Function onPanUpdate;
final Function onPanEnd;
ScaleAndPanRecognizer({
@required this.onPanDown,
@required this.onPanUpdate,
@required this.onPanEnd,
});
int numPointers = 0;
int timeFrame = 1;
int pointer1;
int pointer2;
var time1;
var time2;
var position1;
@override
void addPointer(PointerDownEvent event) {
print(numPointers);
if (numPointers == 0) {
pointer1 = event.pointer;
print(pointer1);
position1 = event.localPosition;
manager.hold(pointer1); //hold the assignment for this pointer for now
startTrackingPointer(pointer1);
numPointers += 1;
time1 = DateTime.now();
} else if (numPointers == 1) {
pointer2 = event.pointer;
print(pointer2);
resolvePointer(pointer2, GestureDisposition.rejected);
time2 = DateTime.now();
var diff = time2.difference(time1);
print(diff);
if (diff <= Duration(seconds: timeFrame)) {
manager.release(pointer1);
resolvePointer(pointer1, GestureDisposition.rejected);
} else {
resolvePointer(pointer1, GestureDisposition.accepted);
manager.release(pointer1);
onPanDown(position1);
}
numPointers = 0;
}
}
@override
void handleEvent(PointerEvent event) {
if (event is PointerMoveEvent) {
onPanUpdate(event.localPosition);
}
if (event is PointerUpEvent) {
onPanEnd();
stopTrackingPointer(event.pointer);
}
}
@override
String get debugDescription => 'only one pointer recognizer';
@override
void didStopTrackingLastPointer(int pointer) {}
}
Upvotes: 8
Views: 7377
Reputation: 41
you dont need pan when you want use scale
there is a properti on scale => pointerCount
if(details.pointerCount == 2){
//we have two finger so we can scale the widget
}else if(details.pointerCount == 1){
//we have one finger so we can do the move or something like we uses in pan
}
Upvotes: 1
Reputation: 1564
What you want to do is to replace onPanUpdate, onPanEnd...
with onScaleUpdate, onScaleEnd...
. Then just instead of details.globalPosition
use details.focalPoint
. You will get the same behaviour as Pan, plus you will now have access to details.scale
or details.rotation
. Here is an example.
Before:
onPanUpdate: (DragUpdateDetails details){
newPosition = details.globalPosition;
//scale and rotation missing in pan
},
After:
onScaleUpdate: (ScaleUpdateDetails details){
newPosition = details.focalPoint;
newRotation = details.rotation;
newScale = details.scale;
//scale and rotation now available
},
Hope this helps. Took me some time to figure it out too.
Upvotes: 4
Reputation: 29
Using Listener widget for listen pointer event, then handle pointer event to detect scale and pan gesture as you need.
you can using gesture_x_detector for full support gestures(tap, double tap, scale, rotate, long press,..) together.
Upvotes: 0