如何在Flutter的小部件测试中执行缩放(捏合缩放)多指手势?

9
我正在编写关于小部件测试的内容,这个小部件在用户执行缩放手势时处理操作,通过实例化一个带有onScaleUpdate属性回调的GestureDetector。我知道如何在小部件测试中进行拖动、点击和长按,但我找不到一种方法来执行缩放手势。
我尝试了几种方法,比如在相反方向上同时拖动:
final myWidget = find.byKey(const Key("myWidget"));
await tester.drag(myWidget, Offset(100, 0));
await tester.drag(myWidget, Offset(-100, 0));

但是拖动操作不能同时发生,框架强制我在执行第二个拖动之前等待第一个拖动完成并使用await关键字。

在小部件测试中是否有执行缩放/捏合/多指手势的方法?

4个回答

1

您可以使用WidgetTestercreateGesture()startGesture()方法创建两个或更多的触摸,并对它们进行控制。以下是一个示例:

    final widgetFinder = find.byKey(ValueKey('Scalable widget'));
    final center = tester.getCenter(widgetFinder);
    
    // create two touches:
    final touch1 = await tester.startGesture(center.translate(-10, 0));
    final touch2 = await tester.startGesture(center.translate(10, 0));

    // zoom in:
    await touch1.moveBy(Offset(-100, 0));
    await touch2.moveBy(Offset(100, 0));
    await tester.pump();
    
    // zoom out:
    await touch1.moveBy(Offset(10, 0));
    await touch2.moveBy(Offset(-10, 0));
    await tester.pump();
    
    // cancel touches:
    await touch1.cancel();
    await touch2.cancel();

0

如果您需要定时缩放,我编写了一个扩展,其中包含timedZoomFrom方法,类似于WidgetControllertimedDragFrom

extension ZoomTesting on WidgetTester{
  Future<void> timedZoomFrom(
      Offset startLocation1,
      Offset offset1,
      Offset startLocation2,
      Offset offset2,
      Duration duration, {
        int? pointer,
        int buttons = kPrimaryButton,
        double frequency = 60.0,
      }) {
    assert(frequency > 0);
    final int intervals = duration.inMicroseconds * frequency ~/ 1E6;
    assert(intervals > 1);
    pointer ??= nextPointer;
    int pointer2 = pointer + 1;
    final List<Duration> timeStamps = <Duration>[
      for (int t = 0; t <= intervals; t += 1)
        duration * t ~/ intervals,
    ];
    final List<Offset> offsets1 = <Offset>[
      startLocation1,
      for (int t = 0; t <= intervals; t += 1)
        startLocation1 + offset1 * (t / intervals),
    ];
    final List<Offset> offsets2 = <Offset>[
      startLocation2,
      for (int t = 0; t <= intervals; t += 1)
        startLocation2 + offset2 * (t / intervals),
    ];
    final List<PointerEventRecord> records = <PointerEventRecord>[
      PointerEventRecord(Duration.zero, <PointerEvent>[
        PointerAddedEvent(
          position: startLocation1,
        ),
        PointerAddedEvent(
          position: startLocation2,
        ),
        PointerDownEvent(
          position: startLocation1,
          pointer: pointer,
          buttons: buttons,
        ),
        PointerDownEvent(
          position: startLocation2,
          pointer: pointer2,
          buttons: buttons,
        ),
      ]),
      ...<PointerEventRecord>[
        for(int t = 0; t <= intervals; t += 1)
          PointerEventRecord(timeStamps[t], <PointerEvent>[
            PointerMoveEvent(
              timeStamp: timeStamps[t],
              position: offsets1[t+1],
              delta: offsets1[t+1] - offsets1[t],
              pointer: pointer,
              buttons: buttons,
            ),
            PointerMoveEvent(
              timeStamp: timeStamps[t],
              position: offsets2[t+1],
              delta: offsets2[t+1] - offsets2[t],
              pointer: pointer2,
              buttons: buttons,
            ),
          ]),
      ],
      PointerEventRecord(duration, <PointerEvent>[
        PointerUpEvent(
          timeStamp: duration,
          position: offsets1.last,
          pointer: pointer,
        ),
        PointerUpEvent(
          timeStamp: duration,
          position: offsets2.last,
          pointer: pointer2,
        ),
      ]),
    ];
    return TestAsyncUtils.guard<void>(() async {
      await handlePointerEventRecord(records);
    });
  }
}

使用示例:

  // fast zoom in
  await tester.timedZoomFrom(
      center.translate(-10, 0), const Offset(-100, 0),
      center.translate(10, 0), const Offset(100, 0),
      const Duration(seconds: 1));

0

你可以使用这个包 pinch_zoom: ^1.0.0


0

这是你可以做到的方法:

// Create the finder
final interactiveViewFinder = find.byType(InteractiveViewer);

// Get the center      
final center = tester.getCenter(interactiveViewFinder);

// Zoom in:
final Offset scaleStart1 = center;
final Offset scaleStart2 = Offset(center.dx + 10.0, center.dy);
final Offset scaleEnd1 = Offset(center.dx - 10.0, center.dy);
final Offset scaleEnd2 = Offset(center.dx + 10.0, center.dy);
final TestGesture gesture = await tester.createGesture();
final TestGesture gesture2 = await tester.createGesture();
await gesture.down(scaleStart1);
await gesture2.down(scaleStart2);
await tester.pump();
await gesture.moveTo(scaleEnd1);
await gesture2.moveTo(scaleEnd2);
await tester.pump();
await gesture.up();
await gesture2.up();
await tester.pumpAndSettle();

源代码:Flutter自己的InteractiveViewer单元测试:https://github.com/flutter/flutter/blob/7d368dcf0c00b45fef5b02c5cccb8aa5306234ba/packages/flutter/test/widgets/interactive_viewer_test.dart#L49


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接