mapbox / mapbox-maps-flutter

Interactive, thoroughly customizable maps for Flutter powered by Mapbox Maps SDK
https://www.mapbox.com/mobile-maps-sdk
Other
276 stars 107 forks source link

BUG: two finger gestures no longer work #439

Open LorenzSchueler opened 6 months ago

LorenzSchueler commented 6 months ago

~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 :)

PaulPickhardt commented 5 months ago

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.

adeveloper-wq commented 5 months ago

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()),
    },
  ),
),
tempo-riz commented 5 months ago

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 commented 5 months ago

Any update / workaround on this ?

adeveloper-wq commented 5 months ago

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

lantah-1 commented 4 months ago

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

hussenIbrahim commented 4 months ago

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

King-Korol commented 3 months ago

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

 gestureRecognizers: {
      Factory<EagerGestureRecognizer>(() => EagerGestureRecognizer()),
    },
adeveloper-wq commented 3 months ago

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.

willipe53 commented 2 months ago

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.

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.