Flutter:GestureArena、RawGestureDetectors 的捏合缩放以及垂直滚动的问题

Las*_*s05 5 user-interface android listview dart flutter

我正在尝试制作一个与 Google 日历周视图完全相同的小部件。这意味着

\n
    \n
  • 捏合缩放
  • \n
  • 垂直滚动
  • \n
\n

这是一个例子

\n

这是示例的GitHub 存储库。

\n

为了简单起见,我想只关注可能的垂直滚动,我可以自己添加其余的。

\n

问题是 PinchToZoom 非常不可靠,即使我进行捏缩放,列表也会开始滚动。为什么会发生这种情况?我做了一些研究并找到了这篇文章

\n

它基本上描述了我的问题的简化版本,即两个手势检测器竞争。解决方案是 RawGestureDetector。我自己写的:

\n
class PinchToZoomGestureRecognizer extends OneSequenceGestureRecognizer {\n  final void Function() onScaleStart;\n  final void Function() onScaleUpdate;\n  final void Function() onScaleEnd;\n\n  PinchToZoomGestureRecognizer({\n    required this.onScaleStart,\n    required this.onScaleUpdate,\n    required this.onScaleEnd,\n  });\n\n  @override\n  String get debugDescription => \'$runtimeType\';\n\n  Map<int, Offset> pointerPositionMap = {};\n\n  @override\n  void addAllowedPointer(PointerEvent event) {\n    startTrackingPointer(event.pointer);\n    pointerPositionMap[event.pointer] = event.position;\n    if (pointerPositionMap.length >= 2) {\n      resolve(GestureDisposition.accepted);\n    }\n  }\n  @override\n  void handleEvent(PointerEvent event) {\n    if (event is PointerMoveEvent) {\n      pointerPositionMap[event.pointer] = event.position;\n      return;\n    } else if (event is PointerDownEvent) {\n      pointerPositionMap[event.pointer] = event.position;\n    } else if (event is PointerUpEvent || event is PointerCancelEvent) {\n      stopTrackingPointer(event.pointer);\n      pointerPositionMap.remove(event.pointer);\n    }\n\n    if (pointerPositionMap.length >= 2) {\n      resolve(GestureDisposition.accepted);\n    }\n  }\n\n  @override\n  void didStopTrackingLastPointer(int pointer) {\n    resolve(GestureDisposition.rejected);\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

所有这一切的目的是,如果有两个或更多指针,则在 GestureArena 中宣布胜利。如果两个指针同时进入竞技场,这种方法就可以正常工作。但是,如果不是,并且 ListView 接受第一个指针,则对于第二个指针,我的 GestureDetector 甚至不会添加到 Arena:

\n
I/flutter (13717): Gesture arena 8    \xe2\x9d\x99 \xe2\x98\x85 Opening new gesture arena.\nI/flutter (13717): Gesture arena 8    \xe2\x9d\x99 Adding: PinchToZoomGestureRecognizer#f9b77\nI/flutter (13717): Gesture arena 8    \xe2\x9d\x99 Adding: VerticalDragGestureRecognizer#07525(start behavior: start)\nI/flutter (13717): Gesture arena 8    \xe2\x9d\x99 Closing with 2 members.\nI/flutter (13717): Gesture arena 8    \xe2\x9d\x99 Accepting: VerticalDragGestureRecognizer#07525(start behavior: start)\nI/flutter (13717): Gesture arena 8    \xe2\x9d\x99 Self-declared winner: VerticalDragGestureRecognizer#07525(start behavior: start)\nD/EGL_emulation(13717): app_time_stats: avg=781.66ms min=5.34ms max=12373.45ms count=16\nI/flutter (13717): Gesture arena 9    \xe2\x9d\x99 \xe2\x98\x85 Opening new gesture arena.\nI/flutter (13717): Gesture arena 9    \xe2\x9d\x99 Adding: VerticalDragGestureRecognizer#07525(start behavior: start)\nI/flutter (13717): Gesture arena 9    \xe2\x9d\x99 Accepting: VerticalDragGestureRecognizer#07525(start behavior: start)\nI/flutter (13717): Gesture arena 9    \xe2\x9d\x99 Closing with 1 member.\nI/flutter (13717): Gesture arena 9    \xe2\x9d\x99 Default winner: VerticalDragGestureRecognizer#07525(start behavior: start)\n
Run Code Online (Sandbox Code Playgroud)\n

这意味着,如果用户没有完美地控制两根手指进行缩放,列表将简单地滚动。

\n

这是我用来测试这个的小部件代码:

\n
I/flutter (13717): Gesture arena 8    \xe2\x9d\x99 \xe2\x98\x85 Opening new gesture arena.\nI/flutter (13717): Gesture arena 8    \xe2\x9d\x99 Adding: PinchToZoomGestureRecognizer#f9b77\nI/flutter (13717): Gesture arena 8    \xe2\x9d\x99 Adding: VerticalDragGestureRecognizer#07525(start behavior: start)\nI/flutter (13717): Gesture arena 8    \xe2\x9d\x99 Closing with 2 members.\nI/flutter (13717): Gesture arena 8    \xe2\x9d\x99 Accepting: VerticalDragGestureRecognizer#07525(start behavior: start)\nI/flutter (13717): Gesture arena 8    \xe2\x9d\x99 Self-declared winner: VerticalDragGestureRecognizer#07525(start behavior: start)\nD/EGL_emulation(13717): app_time_stats: avg=781.66ms min=5.34ms max=12373.45ms count=16\nI/flutter (13717): Gesture arena 9    \xe2\x9d\x99 \xe2\x98\x85 Opening new gesture arena.\nI/flutter (13717): Gesture arena 9    \xe2\x9d\x99 Adding: VerticalDragGestureRecognizer#07525(start behavior: start)\nI/flutter (13717): Gesture arena 9    \xe2\x9d\x99 Accepting: VerticalDragGestureRecognizer#07525(start behavior: start)\nI/flutter (13717): Gesture arena 9    \xe2\x9d\x99 Closing with 1 member.\nI/flutter (13717): Gesture arena 9    \xe2\x9d\x99 Default winner: VerticalDragGestureRecognizer#07525(start behavior: start)\n
Run Code Online (Sandbox Code Playgroud)\n

请注意,我实际上并没有实现捏缩放,因为这很简单,它只是让 GestureDetector 首先识别手势。

\n

如果有人可以帮助我采用完全不同的方法来缩放 ListView,或者知道 RawGestureDetector 的工作原理以及为什么在这种情况下它不起作用,我将非常感激。

\n

知道如何制作可靠的捏合缩放小部件吗?

\n

raj*_*tty 0

当我在列表旁边有一个地图并且地图支持捏合手势时,我在 GoogleMap 中使用了带有 EagerGestureRecognizer 的手势识别器,看看这是否有帮助

 gestureRecognizers: <Factory<OneSequenceGestureRecognizer>>[
          Factory<OneSequenceGestureRecognizer>(
            () => EagerGestureRecognizer(),
          ),
        ].toSet(),
Run Code Online (Sandbox Code Playgroud)