将水平滚动与WebView结合使用时的滚动优先级

Lud*_*mer 7 flutter flutter-plugin

我有一个WebView水平滚动里面的垂直滚动PageView。像这样:

PageView.builder(
  itemCount: 5,
  itemBuilder: (context, index) {
    return WebView(
      initialUrl: 'https://flutter.dev/docs',
      gestureRecognizers: [
        Factory(() => VerticalDragGestureRecognizer()),
      ].toSet(),
    );
  },
);
Run Code Online (Sandbox Code Playgroud)

在Flutter的先前稳定版本(1.5.4)中,此操作按预期工作-垂直滚动将在WebView中移动内容,水平滚动将在PageView中移动。

升级到Flutter后,此操作中断了v1.7.8+hotfix.3。现在,即使手势几乎完全是垂直的,水平滚动似乎总是可以取胜的。如果页面完全垂直滚动,则仅在手势停止之后(即,当我在手势之后停止触摸屏幕时)-在手势发生时不会进行垂直滚动。

添加和删除VerticalDragGestureRecognizergestureRecognizers没有任何效果现在-无论哪种方式,程序,工作起来就像识别器不在名单上(尽管这并不是说gestureRecognizers完全忽略,因为加入EagerGestureRecognizer确实有效果)。

这是手势竞技场的调试输出(请记住,我试图将笔势保持尽可能垂直,但是即使HorizontalDragGestureRecognizer我也垂直移动了手势,即使手指稍微向两侧移动也足以赢得胜利。全部时间):

I/flutter (30125): Gesture arena 14   ? ? Opening new gesture arena.
I/flutter (30125): Gesture arena 14   ? Adding: Instance of '_CombiningGestureArenaMember'
I/flutter (30125): Gesture arena 14   ? Adding: LongPressGestureRecognizer#9cad1(debugOwner: GestureDetector, state: ready)
I/flutter (30125): Gesture arena 14   ? Adding: HorizontalDragGestureRecognizer#69b8f(start behavior: start)
I/flutter (30125): Gesture arena 14   ? Closing with 3 members.
I/flutter (30125): Gesture arena 14   ? Rejecting: LongPressGestureRecognizer#9cad1(debugOwner: GestureDetector, state: possible)
I/flutter (30125): Gesture arena 14   ? Accepting: HorizontalDragGestureRecognizer#69b8f(start behavior: start)
I/flutter (30125): Gesture arena 14   ? Self-declared winner: HorizontalDragGestureRecognizer#69b8f(start behavior: start)
Run Code Online (Sandbox Code Playgroud)

这就是当您在拖动手势进行时设法保持手势完全垂直(似乎在使用鼠标的模拟器上更容易)时发生的情况:

flutter: Gesture arena 30   ? ? Opening new gesture arena.
flutter: Gesture arena 30   ? Adding: Instance of '_CombiningGestureArenaMember'
flutter: Gesture arena 30   ? Adding: HorizontalDragGestureRecognizer#11e7f(start behavior: down)
flutter: Gesture arena 30   ? Closing with 2 members.
Run Code Online (Sandbox Code Playgroud)

即使是轻微的垂直移动也可以使HorizontalDragGestureRecognizer宣布获胜,但是VerticalDragGestureRecognizer(似乎包裹在中_CombiningGestureArenaMember)永远不会要求胜利。这似乎在事实上被完全忽略-手势舞台输出,VerticalDragGestureRecognizergestureRecognizers没有它是完全一致的。

这可能是Flutter中的错误,因此我还在Flutter的GitHub上创建了一个问题。但是,无论哪种方式-如何在当前版本的Flutter中达到这种效果?任何解决方法或规范解决方案将不胜感激。

Sae*_*bil 29

竞技场的规则好像变了。现在,竞技场宣布具有活动接收器的手势获胜。这确实进一步提高了手势的响应能力。但是,由于本机视图不要求手势,并且仅在没有其他活动检测器/接收器要求它们时才使用它们,我怀疑垂直拖动甚至不会作为来自 WebView 的手势进入竞技场。这就是为什么任何轻微的水平拖动都会导致水平拖动手势获胜 - 因为根本没有其他小部件要求任何手势。

您可以扩展VerticalDragGestureRecognizer,因此它接受手势:

class PlatformViewVerticalGestureRecognizer
    extends VerticalDragGestureRecognizer {
  PlatformViewVerticalGestureRecognizer({PointerDeviceKind kind})
      : super(kind: kind);

  Offset _dragDistance = Offset.zero;

  @override
  void addPointer(PointerEvent event) {
    startTrackingPointer(event.pointer);
  }

  @override
  void handleEvent(PointerEvent event) {
    _dragDistance = _dragDistance + event.delta;
    if (event is PointerMoveEvent) {
      final double dy = _dragDistance.dy.abs();
      final double dx = _dragDistance.dx.abs();

      if (dy > dx && dy > kTouchSlop) {
        // vertical drag - accept
        resolve(GestureDisposition.accepted);
        _dragDistance = Offset.zero;
      } else if (dx > kTouchSlop && dx > dy) {
        // horizontal drag - stop tracking
        stopTrackingPointer(event.pointer);
        _dragDistance = Offset.zero;
      }
    }
  }

  @override
  String get debugDescription => 'horizontal drag (platform view)';

  @override
  void didStopTrackingLastPointer(int pointer) {}
}
Run Code Online (Sandbox Code Playgroud)

之后,您可以在gestureRecognizers以下位置使用新类:

PageView.builder(
  itemCount: 5,
  itemBuilder: (context, index) {
    return WebView(
      initialUrl: 'https://flutter.dev/docs',
      gestureRecognizers: [
        Factory(() => PlatformViewVerticalGestureRecognizer()),
      ].toSet(),
    );
  },
);
Run Code Online (Sandbox Code Playgroud)

  • 这个版本运行完美。我继续对你的答案进行了一些清理(因此它包含一个单一的、规范的、随时可用的答案 - 我希望你不介意),接受它并授予你赏金。感谢您的所有帮助! (2认同)
  • 谢谢,这是一个非常有趣的问题,今天我学到了很多东西。 (2认同)