Open ojciec-dev opened 11 months ago
This is a really tricky limitation in Flutter, since scale is a superset of pan. We could possibly work around it by using the scale detector for panning too, but I don't think that multi touch would work properly if we did that. If anyone has a good solution for this we are all ears!
With regular Flutter widgets you can put Draggable
inside InteractiveViewer
and both drag and scale gestures work in the same time. I'm sure there is a way to do this and keep multitouch functional.
For now I was forced to stop using Flame for this very reason as I was unable to find a workaround on my end. What I tried was adding at first non-draggable Component, and then replacing it with a draggable Component after it was touched. Then on tapping outside - replacing draggable with non-draggable. This worked but only one time, looks like adding a Component with DragCallbacks
will register a listener, but removing this component won't unregister that listener and this listener will steal the touch inputs after even though it's not doing anything.
I also tried adding/removing listeners manually, but part of the Flame impl is internal and I couldn't do it.
I'm sure there is a way to do this and keep multitouch functional.
How would it be able to detect whether multiple fingers on the screen are moving independently or doing a scale gesture? Possibly we could have an implementation that supports one-finger drags and scaling at the same time, but I think it is basically impossible to support two finger scaling and multi-finger dragging at the same time since a lot of the drag events would register as scale events.
This worked but only one time, looks like adding a Component with DragCallbacks will register a listener
You can remove this listener by doing this I think:
game.findByKey(MultiDragDispatcherKey()).removeFromParent();
@spydon, I read my previous message and I see it's confusing, apologies
put Draggable inside InteractiveViewer and both drag and scale gestures work in the same time
what I meant is you can either drag a Draggable or scale with InteractiveViewer - depending what takes the touch input first, but you can perform both actions. My use case is being able to position elements on the screen with precision, and since elements can vary in size I need to be able to zoom in to be able to grab the smaller ones.
When you put a Draggable
inside of an InteractiveViewer
, you don't have multi touch support anymore, right?
Because the scale events will always (or a lot of the time) win on the gesture arena as soon as there are multiple fingers involved.
So what I'm suggesting is to create a new event dispatcher that registers a DragGestureRecognizer
(monodrag) which should be possible to use together with a ScaleDetector
/ScaleGestureRecognizer
.
It should be fairly easy, mostly copying the current MultiDragDispatcher
implementation and create something like MonoDragDispatcher
and then add a boolean to DragCallbacks
that indicates whether it should register a mono- or multi-dispatcher. And probably have an assertion if it finds out that there are different types trying to be registered at the same time.
No, you still get multitouch working, it just depends on what you click on first. From my experience:
You can see it working here: https://github.com/flame-engine/flame/assets/46694136/5f4629d0-9c54-41fa-8e1e-b6583bb44ef8
Thanks for the hints how to implement similar behavior with Flame.
No, you still get multitouch working, it just depends on what you click on first. From my experience:
Interesting, there must be some really delicate work done in the gesture arena for that to work.
Thanks for the hints how to implement similar behavior with Flame.
If you want to implement it in Flame, do you want to make a PR with it? In that case i can assign you to the issue. :) You can of course ask me if you need any pointers too.
We moved away from Flame for now, I used at first to get the collision detection for free, but after I stumbled upon this issue I switched over to standard Flutter to be able to move forward. Down the road we might need some Flame magic, but util that happens I need to focus on other things.
Linking #2726 here since it is related.
Is there a workaround for this?
I faced the opposite of the original issue -- i.e. DragCallbacks
on a child component does not work properly with ScaleDetector
as a parent component.
In the video snippet below, you'll notice after zooming in then zooming out, dragging with a single finger invokes onScaleStart
instead of onDragStart
most of the time. In some cases, even tapping on on the game invokes onScaleStart
.
https://github.com/flame-engine/flame/assets/46427323/f8e5ef77-7a94-4bc6-a2df-dcea0f767847
For reference, I've already faced a similar issue with InteractiveViewer
before and I've a bug filed in flutter repo: https://github.com/flutter/flutter/issues/136622
Just to follow up:
The issue I reported above was a bug in the engine and it was fixed in:
Also, not sure if it'll help here, but the pointerCount
for the trackpad was also updated:
Now trackpad gestures will count as pointerCount=2 instead of 1. It makes it easier for people who want to have different behaviour for single-finger drag vs two-finger pan/zoom.
both fixes should be in master by now.
Cheers
Thanks for the update @osaxma, this should have a separate issue though since it's not the same as the one OP describes.
Current bug behavior
ScaleDetector
doesn't work when a Component withDragCallbacks
is added.Expected behavior
Scale gesture (pinch-to-zoom) should work regardless if a Component with
DragCallbacks
is registered. I'd expect to distinguish between two-finger scale gestures from one-finger tap and drag gestures.In the example below you can drag the green rectangle but you cannot scale the board. When you remove
DragCallbacks
mixin, scale gesture starts working.Steps to reproduce
ScaleDetector
with FlutterGameDragCallbacks
onScaleUpdate
is not being called after scale gestureDragCallbacks
mixin and noticeonScaleUpdate
is now being calledFlutter doctor output
More environment information
More information
I want to have draggable components placed on the zoomable board. Imagine you have a puzzle board and you want to zoom in to be able to drag the smaller pieces with precision.
DragCallbacks
is taking over all touch inputs even when they happen outside of the Component. I see under the hood that whenever a Component with DragCallbacks is addedImmediateMultiDragGestureRecognizer
is registered as one of the gestureDetectors (here).