flingFrom method

Future<void> flingFrom (Offset startLocation, Offset offset, double speed, { int pointer, Duration frameInterval: const Duration(milliseconds: 16), Offset initialOffset: Offset.zero, Duration initialOffsetDelay: const Duration(seconds: 1) })

Attempts a fling gesture starting from the given location, moving the given distance, reaching the given speed.

Exactly 50 pointer events are synthesized.

The offset and speed control the interval between each pointer event. For example, if the offset is 200 pixels down, and the speed is 800 pixels per second, the pointer events will be sent for each increment of 4 pixels (200/50), over 250ms (200/800), meaning events will be sent every 1.25ms (250/200).

To make tests more realistic, frames may be pumped during this time (using calls to pump). If the total duration is longer than frameInterval, then one frame is pumped each time that amount of time elapses while sending events, or each time an event is synthesized, whichever is rarer.

A fling is essentially a drag that ends at a particular speed. If you just want to drag and end without a fling, use dragFrom.

The initialOffset argument, if non-zero, causes the pointer to first apply that offset, then pump a delay of initialOffsetDelay. This can be used to simulate a drag followed by a fling, including dragging in the opposite direction of the fling (e.g. dragging 200 pixels to the right, then fling to the left over 200 pixels, ending at the exact point that the drag started).

Implementation

Future<void> flingFrom(
  Offset startLocation,
  Offset offset,
  double speed, {
  int pointer,
  Duration frameInterval = const Duration(milliseconds: 16),
  Offset initialOffset = Offset.zero,
  Duration initialOffsetDelay = const Duration(seconds: 1),
}) {
  assert(offset.distance > 0.0);
  assert(speed > 0.0); // speed is pixels/second
  return TestAsyncUtils.guard<void>(() async {
    final TestPointer testPointer = TestPointer(pointer ?? _getNextPointer());
    final HitTestResult result = hitTestOnBinding(startLocation);
    const int kMoveCount = 50; // Needs to be >= kHistorySize, see _LeastSquaresVelocityTrackerStrategy
    final double timeStampDelta = 1000.0 * offset.distance / (kMoveCount * speed);
    double timeStamp = 0.0;
    double lastTimeStamp = timeStamp;
    await sendEventToBinding(testPointer.down(startLocation, timeStamp: Duration(milliseconds: timeStamp.round())), result);
    if (initialOffset.distance > 0.0) {
      await sendEventToBinding(testPointer.move(startLocation + initialOffset, timeStamp: Duration(milliseconds: timeStamp.round())), result);
      timeStamp += initialOffsetDelay.inMilliseconds;
      await pump(initialOffsetDelay);
    }
    for (int i = 0; i <= kMoveCount; i += 1) {
      final Offset location = startLocation + initialOffset + Offset.lerp(Offset.zero, offset, i / kMoveCount);
      await sendEventToBinding(testPointer.move(location, timeStamp: Duration(milliseconds: timeStamp.round())), result);
      timeStamp += timeStampDelta;
      if (timeStamp - lastTimeStamp > frameInterval.inMilliseconds) {
        await pump(Duration(milliseconds: (timeStamp - lastTimeStamp).truncate()));
        lastTimeStamp = timeStamp;
      }
    }
    await sendEventToBinding(testPointer.up(timeStamp: Duration(milliseconds: timeStamp.round())), result);
  });
}