trackpadFlingFrom method
Attempts a fling gesture starting from the given location, moving the given distance, reaching the given speed. A trackpad fling sends PointerPanZoom events instead of a sequence of touch events.
This can pump frames.
Exactly 50 pointer events are synthesized.
The speed
is in pixels per second in the direction given by offset
.
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.
See LiveTestWidgetsFlutterBindingFramePolicy.benchmarkLive if the method is used in a live environment and accurate time control is important.
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).
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.
Implementation
Future<void> trackpadFlingFrom(
Offset startLocation,
Offset offset,
double speed, {
int? pointer,
int buttons = kPrimaryButton,
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(), PointerDeviceKind.trackpad, null, buttons);
const int kMoveCount = 50; // Needs to be >= kHistorySize, see _LeastSquaresVelocityTrackerStrategy
final double timeStampDelta = 1000000.0 * offset.distance / (kMoveCount * speed);
double timeStamp = 0.0;
double lastTimeStamp = timeStamp;
await sendEventToBinding(testPointer.panZoomStart(startLocation, timeStamp: Duration(microseconds: timeStamp.round())));
if (initialOffset.distance > 0.0) {
await sendEventToBinding(testPointer.panZoomUpdate(startLocation, pan: initialOffset, timeStamp: Duration(microseconds: timeStamp.round())));
timeStamp += initialOffsetDelay.inMicroseconds;
await pump(initialOffsetDelay);
}
for (int i = 0; i <= kMoveCount; i += 1) {
final Offset pan = initialOffset + Offset.lerp(Offset.zero, offset, i / kMoveCount)!;
await sendEventToBinding(testPointer.panZoomUpdate(startLocation, pan: pan, timeStamp: Duration(microseconds: timeStamp.round())));
timeStamp += timeStampDelta;
if (timeStamp - lastTimeStamp > frameInterval.inMicroseconds) {
await pump(Duration(microseconds: (timeStamp - lastTimeStamp).truncate()));
lastTimeStamp = timeStamp;
}
}
await sendEventToBinding(testPointer.panZoomEnd(timeStamp: Duration(microseconds: timeStamp.round())));
});
}