mapbox-maps-flutter icon indicating copy to clipboard operation
mapbox-maps-flutter copied to clipboard

BUG: two finger gestures no longer work

Open LorenzSchueler opened this issue 1 year ago • 10 comments

~Suddenly~ After upgrading flutter to 3.19, I can no longer zoom using pinch to zoom or rotate the map using two fingers. When I do so I get: W/MultiFingerGesture(18269): Some MotionEvents were not passed to the library or events from different view trees are merged. which is created here: https://github.com/mapbox/mapbox-gestures-android/blob/60bcff932b6fc00d1fa4dab660af8787aaa48369/library/src/main/java/com/mapbox/android/gestures/MultiFingerGesture.java#L97-L100

Single finger gestures (like moving around or double tap to zoom in) still work.

I haven't changed anything related to mapbox in my app. ~Although I'm not completely sure this might have started after I upgraded flutter to 3.19 but I'm not quite sure it was not there before.~ After downgrading flutter to 3.16.9 it works again.

Do you have any ideas what might cause this?

Thanks for all the effort with this library :)

LorenzSchueler avatar Mar 11 '24 15:03 LorenzSchueler

In our case we have a GestureDetecor above the map widget to catch long presses. After upgrading to Flutter to 3.19.x scale gestures no longer work for the mapbox widget.

We tested the GestureDetector behavior on a minimal example like this:

GestureDetector(
        onLongPressDown: (details) => print("DOWN"),
        onLongPressCancel: () => print("CANCEL"),
        onLongPressMoveUpdate: (details) => print("UPDATE"),
        onLongPressEnd: (details) => print("END"),
        behavior: HitTestBehavior.translucent,
        child: GestureDetector(
          onScaleStart: (details) => print("SCALE START"),
          onScaleEnd: (details) => print("SCALE END"),
          behavior: HitTestBehavior.translucent,
          child: Container(
            width: MediaQuery.of(context).size.width,
            height: MediaQuery.of(context).size.height,
            color: Colors.blue,
          ),
        ),
      ),

This works as expected.

If you replace the second GestureDetector with the mapbox widget, it does not work.

Edit: It's also worth mentioning that it's only a problem on Android devices. iOS works fine.

PaulPickhardt avatar Mar 20 '24 15:03 PaulPickhardt

Adding some more examples to the comment of @PaulPickhardt .

In the following example, zooming by doing the two-finger-gesture does not work (on Android). Only DOWN, CANCEL, UPDATE, END gets logged while doint the long press gestures. When doing the zoom-gesture, the following appears a lot in the log: W/MultiFingerGesture(29816): Some MotionEvents were not passed to the library or events from different view trees are merged.

GestureDetector(
  onLongPressDown: (details) => print("DOWN"),
  onLongPressCancel: () => print("CANCEL"),
  onLongPressMoveUpdate: (details) => print("UPDATE"),
  onLongPressEnd: (details) => print("END"),
  child: MapWidget(
      textureView: true,
    ),
)

The same behavior can be seen with the following example.

GestureDetector(
  onLongPressDown: (details) => print("DOWN"),
  onLongPressCancel: () => print("CANCEL"),
  onLongPressMoveUpdate: (details) => print("UPDATE"),
  onLongPressEnd: (details) => print("END"),
  child: MapWidget(
    textureView: true,
    gestureRecognizers: {
      Factory<ScaleGestureRecognizer>(() => ScaleGestureRecognizer()),
    },
  ),
),

In the last example, the zoom gesture works and nothing gets logged while doing so. However, when doing the long-press, only DOWN but no other callbacks are triggered.

GestureDetector(
  onLongPressDown: (details) => print("DOWN"),
  onLongPressCancel: () => print("CANCEL"),
  onLongPressMoveUpdate: (details) => print("UPDATE"),
  onLongPressEnd: (details) => print("END"),
  child: MapWidget(
    textureView: true,
    gestureRecognizers: {
      Factory<EagerGestureRecognizer>(() => EagerGestureRecognizer()),
    },
  ),
),

adeveloper-wq avatar Mar 21 '24 07:03 adeveloper-wq

I think it's related to this : https://github.com/flutter/flutter/pull/136708

I found it with ctrl+F of "gesture" in flutter 3.19 changelogs : https://docs.flutter.dev/release/release-notes/release-notes-3.19.0

Update :

https://docs.flutter.dev/release/breaking-changes/multi-touch-scrolling I think this might be useful :)

tempo-riz avatar Apr 04 '24 11:04 tempo-riz

Any update / workaround on this ?

tempo-riz avatar Apr 08 '24 13:04 tempo-riz

As a workaround, we stick with Flutter 3.16.9 for now.

adeveloper-wq avatar Apr 08 '24 13:04 adeveloper-wq

the same issue for me. i downgrade to 3.16.x get great.

lantah-1 avatar Apr 30 '24 09:04 lantah-1

try to add gestureRecognizers:<Factory<OneSequenceGestureRecognizer>>{ Factory<OneSequenceGestureRecognizer>(() => EagerGestureRecognizer()), Factory<ScaleGestureRecognizer>(() => ScaleGestureRecognizer()), }

hussenIbrahim avatar May 08 '24 12:05 hussenIbrahim

With this parameter it's work for me. Flutter 3.19.3

 gestureRecognizers: {
      Factory<EagerGestureRecognizer>(() => EagerGestureRecognizer()),
    },

King-Korol avatar May 21 '24 06:05 King-Korol

This was already known (see my comment from March). @King-Korol @lantah-1

In the last example, the zoom gesture works and nothing gets logged while doing so. However, when doing the long-press, only DOWN but no other callbacks are triggered.

GestureDetector(
  onLongPressDown: (details) => print("DOWN"),
  onLongPressCancel: () => print("CANCEL"),
  onLongPressMoveUpdate: (details) => print("UPDATE"),
  onLongPressEnd: (details) => print("END"),
  child: MapWidget(
    textureView: true,
    gestureRecognizers: {
      Factory<EagerGestureRecognizer>(() => EagerGestureRecognizer()),
    },
  ),
),

However, the problem is that by doing so the MapWidget consumes all gestures (even unecessary ones). Other widgets that may need to detect gestures as well may lose their functionality (see the example with the gesture detector). Therefore, this is a workaround that only works in some situations.

adeveloper-wq avatar May 21 '24 06:05 adeveloper-wq

Is there any status update on this issue?

In my own case, I need the Android version of the app to behave as the iOS version does, in which a GestureDetector that consumes long press gestures has a child: MapWidget that consumes scale gestures. The reason I need to wrap the MapWidget in a GestureDetector is because MapWidget does not recognize a drag event on a feature.

  • The scale gestures behave correctly if I use the workaround above: MapWidget(gestureRecognizers: Platform.isAndroid ? { Factory<EagerGestureRecognizer>(() => EagerGestureRecognizer()), ..., but now MapWidget consumes everything so the GestureRecognizer no longer receives long presses.
  • MapWidget(gestureRecognizers: Platform.isAndroid ? { Factory<ScaleGestureRecognizer>(() => ScaleGestureRecognizer()), ... just plain does nothing.
  • A MapWidget without a gestureRecognizers parameter (i.e., passing null) sees Scale Gestures not working but long press now able to be consumed by the GestureDetector.

So no solution yet.

Is there a way to create a custom recognizer that can be passed in the manner of Factory<PinchRecognizer>(() => PinchRecognizer()). I tried this, but it was not successful:

class PinchRecognizer extends ScaleGestureRecognizer {
  PinchRecognizer({super.debugOwner});

  @override
  void addPointer(PointerDownEvent event) {
    // Accept the pointer if it’s the start of a scale gesture
    startTrackingPointer(event.pointer);
    resolve(GestureDisposition.accepted);
    super.addPointer(event);
  }
}

Any thoughts appreciated.

willipe53 avatar Jun 17 '24 13:06 willipe53