GestureDetector: how to distinguish between single touch and multi-touch gestures? - flutter

My goal is to build a widget that allows to draw using single finger tap, and scale/move the canvas when in two-fingers mode.
At the moment I had built a ZoomView and DrawingOverlay widgets. ZoomView allows to scale and move the child passed as parameter. And DrawingOverlay allows to draw on top of the child widget passed as parameter. Right now they work well separately.
class ZoomView {
build() {
return GestureDetector(
onScaleUpdate: () { ... }
...
)
}
}
class DrawingOverlay {
build() {
return GestureDetector(
onPanUpdate: () { ... }
...
)
}
}
However when they are used together, things break apart:
build() {
ZoomView(
child: DrawingOverlay(
child: ...
)
)
}
Priority feels largely by chance. Sometimes it's starts drawing when 2 fingers are pressed and sometimes it's moving the screen with one finger while sometimes the other way round.
I would like to limit ZoomView to 2 finger gestures only and DrawingOverlay to 1 finger gestures only.
What's the best way to achieve this?

It should work setting both the listeners on the same GestureDetector.

Related

How to absorb swipe motion only in Flutter

I am looking for a widget, analogous to AbsorbPointer, that would absorb swipe motions. The goal is to allow "tap" actions to go through to the child but let the parent handle the "swipe" motions.
If possible I would like to also differentiate absorption depending on direction (only absorb vertical motion for example).
Thank you for your help,
you can use GestureDetector to detect tap behavior and swipe motions
GestureDetector(
child: Widget(), // your widget
onTap: () { // Tap behavior listener
// your tap logic
},
onHorizontalDragUpdate: (DragUpdateDetails details) { // Swipe behavior listener
print(details.primaryDelta); // Positive is left to right, Negative is right to left
// your swipe logic
},
)
using two GestureDetector you can warp the parent with listener onHorizontalDragUpdate to detect the swipe motion while warping the child with listener onTap to detect the tap behavior

How to detect multiple gestures using a single instance of GestureDetector?

I want make WhatsApp voice audio record function. User tap and hold to record audio but can swipe left to cancel. But when I use GestureDetector it only register one gesture type.
For example this only register onLongPress gesture if user start with long press. Or only onHorizontalDrag if user start with horizontal drag:
onLongPressStart: _onPressStart,
onLongPressUp: _onPressEnd,
onHorizontalDragDown: _onHorizontalDragDown,
onHorizontalDragUpdate: _onHorizontalDragUpdate,
onHorizontalDragEnd: _onHorizontalDragEnd,
How to use 2 gesture one after the other?
Thanks!
Try using onLongPressMoveUpdate callback provided by GestureDetector
This provides LongPressMoveUpdateDetails which has a property called offsetFromOrigin.
offsetFromOrigin gives you an Offset object whose dx value is what you need.
GestureDetector(
child: ...
onLongPressMoveUpdate: (updateDetails) {
if (updateDetails.offsetFromOrigin.dx < 0) {
// Handle horizontal drag towards left
}
}
)
Or, if you can't use the above method, checkout this Medium article

Flutter PointerEvent vs OnTap, one works, the other doesn't

I have a stack widget I am trying to create in which:
1. The user touches the widget button triggering a pointerDown event.
2. Pointer down causes a slider type widget to scale from 0 to 100% from behind the button
3. With finger still down, the user drags to select a value on the scale
4. The value is selected by releasing the finger from the screen i.e. pointerUp.
The widget works fine when I use onTap instead of pointerDown in step 1. But when I try to use a pointer down event, the _open method (that manages the scaleUp of the slider) isn't triggered.
I have followed this example almost exactly: https://fireship.io/lessons/flutter-radial-menu-staggered-animations/, but have tried to change the touch event on the floatingActionbuton like this:
Transform.scale(
scale: widget.scale.value,
child: Listener(
onPointerDown: (PointerDownEvent event) {
print('pointer is down');
setState(() {
_open;
});
},
child: FloatingActionButton(child: Icon(Icons.blur_circular), onPressed: () {})),
)
The print part detects and fires the event, but the _open method does not do anything and the menu part does not appear like in the tutorial link.
I am at a loss.
Since the button below the FloatingActionButton also has a listener, The Listener widget doesn't get's the PointerDown event. So to do that you have to change the behaviour to opaque so that both get the events.
Try Something like this:
Listener(
behavior: HitTestBehavior.opaque,
onPointerDown: (PointerDownEvent details){
},
child: ...,
)

How to dismiss flutter dismissable widget programmatically?

Is it possible to dismiss dismissable programmatically? Not by swipe, but by let's say button click.
The only thing that comes in mind is imitating gesture event with a certain velocity, but this sounds horribly wrong.
How about considering an AnimatedList instead.
A scrolling container that animates items when they are inserted or removed.
This widget is similar to one created by ListView.builder.
Please try this.
key: Key(UniqueKey().toString()),
2nd Way
onDismissed: (DismissDirection direction) { dismissViewList(ObjecClass); }
And function is :
dismissViewList(ObjecClass) {
if (_personList.contains(ObjecClass)) {
//_personList is list of ObjecClass shown in ListView
setState(() {
_personList.remove(ObjecClass);
});
}
}

How to get the touch position while dragging

I would like to get the touch position while dragging and perform a setState(position). (In Android: getTouchPositionFromDragEvent). I can't find anything that I could use in the Draggable class but maybe there is a work around?
You should use GestureDetector for that:
for example:
GestureDetector(
onVerticalDragDown: (DragDownDetails details) {
print(details.globalPosition);
},
child: // ...
)
see https://docs.flutter.io/flutter/widgets/GestureDetector-class.html
for more detail.
Or you could use a Listener to get raw data Pointer position.
Listener(
onPointerDown: (PointerDownEvent event) {
print(event.position);
},
child: // ...
)
See https://flutter.io/gestures/ to have a comparison between Listener and GestureDetector.