Apply carriedVelocity unless substantially different (#79382)

This commit is contained in:
Trym Nilsen 2021-04-02 23:44:03 +02:00 committed by GitHub
parent d051336451
commit ee921e6313
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 36 additions and 3 deletions

View file

@ -274,6 +274,14 @@ class ScrollDragController implements Drag {
static const Duration momentumRetainStationaryDurationThreshold =
Duration(milliseconds: 20);
/// The minimum amount of velocity needed to apply the [carriedVelocity] at
/// the end of a drag. Expressed as a factor. For example with a
/// [carriedVelocity] of 2000, we will need a velocity of at least 1000 to
/// apply the [carriedVelocity] as well. If the velocity does not meet the
/// threshold the the [carriedVelocity] is lost. Decided by fair eyeballing
/// with the scroll_overlay platform test.
static const double momentumRetainVelocityThresholdFactor = 0.5;
/// Maximum amount of time interval the drag can have consecutive stationary
/// pointer update events before needing to break the
/// [motionStartDistanceThreshold] to start motion again.
@ -390,9 +398,17 @@ class ScrollDragController implements Drag {
velocity = -velocity;
_lastDetails = details;
// Build momentum only if dragging in the same direction.
if (_retainMomentum && velocity.sign == carriedVelocity!.sign)
velocity += carriedVelocity!;
if (_retainMomentum) {
// Build momentum only if dragging in the same direction.
final bool isFlingingInSameDirection = velocity.sign == carriedVelocity!.sign;
// Build momentum only if the velocity of the last drag was not
// substantially lower than the carried momentum.
final bool isVelocityNotSubstantiallyLessThanCarriedMomentum =
velocity.abs() > carriedVelocity!.abs() * momentumRetainVelocityThresholdFactor;
if(isFlingingInSameDirection && isVelocityNotSubstantiallyLessThanCarriedMomentum) {
velocity += carriedVelocity!;
}
}
delegate.goBallistic(velocity);
}

View file

@ -178,6 +178,23 @@ void main() {
expect(getScrollVelocity(tester), moreOrLessEquals(1000.0));
});
testWidgets('A slower final fling does not apply carried momentum', (WidgetTester tester) async {
await pumpTest(tester, debugDefaultTargetPlatformOverride);
await tester.fling(find.byType(Scrollable), const Offset(0.0, -dragOffset), 1000.0);
await tester.pump(); // trigger fling
await tester.pump(const Duration(milliseconds: 10));
// Repeat the exact same motion to build momentum.
await tester.fling(find.byType(Scrollable), const Offset(0.0, -dragOffset), 1000.0);
await tester.pump(); // trigger the second fling
await tester.pump(const Duration(milliseconds: 10));
// Make a final fling that is much slower.
await tester.fling(find.byType(Scrollable), const Offset(0.0, -dragOffset), 200.0);
await tester.pump(); // trigger the third fling
await tester.pump(const Duration(milliseconds: 10));
// expect that there is no carried velocity
expect(getScrollVelocity(tester), lessThan(200.0));
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
testWidgets('No iOS/macOS momentum build with flings in opposite directions', (WidgetTester tester) async {
await pumpTest(tester, debugDefaultTargetPlatformOverride);
await tester.fling(find.byType(Scrollable), const Offset(0.0, -dragOffset), 1000.0);