Unverified Commit 4ab29de6 authored by Casey Rogers's avatar Casey Rogers Committed by GitHub

Cancel DraggableScrollableSheet ballistic animation if a new activity begins (#86614)

parent 3d47dd85
...@@ -10,6 +10,7 @@ import 'framework.dart'; ...@@ -10,6 +10,7 @@ import 'framework.dart';
import 'inherited_notifier.dart'; import 'inherited_notifier.dart';
import 'layout_builder.dart'; import 'layout_builder.dart';
import 'notification_listener.dart'; import 'notification_listener.dart';
import 'scroll_activity.dart';
import 'scroll_context.dart'; import 'scroll_context.dart';
import 'scroll_controller.dart'; import 'scroll_controller.dart';
import 'scroll_notification.dart'; import 'scroll_notification.dart';
...@@ -431,9 +432,17 @@ class _DraggableScrollableSheetScrollPosition ...@@ -431,9 +432,17 @@ class _DraggableScrollableSheetScrollPosition
); );
VoidCallback? _dragCancelCallback; VoidCallback? _dragCancelCallback;
VoidCallback? _ballisticCancelCallback;
final _DraggableSheetExtent extent; final _DraggableSheetExtent extent;
bool get listShouldScroll => pixels > 0.0; bool get listShouldScroll => pixels > 0.0;
@override
void beginActivity(ScrollActivity? newActivity) {
// Cancel the running ballistic simulation, if there is one.
_ballisticCancelCallback?.call();
super.beginActivity(newActivity);
}
@override @override
bool applyContentDimensions(double minScrollExtent, double maxScrollExtent) { bool applyContentDimensions(double minScrollExtent, double maxScrollExtent) {
// We need to provide some extra extent if we haven't yet reached the max or // We need to provide some extra extent if we haven't yet reached the max or
...@@ -481,6 +490,9 @@ class _DraggableScrollableSheetScrollPosition ...@@ -481,6 +490,9 @@ class _DraggableScrollableSheetScrollPosition
debugLabel: objectRuntimeType(this, '_DraggableScrollableSheetPosition'), debugLabel: objectRuntimeType(this, '_DraggableScrollableSheetPosition'),
vsync: context.vsync, vsync: context.vsync,
); );
// Stop the ballistic animation if a new activity starts.
// See: [beginActivity].
_ballisticCancelCallback = ballisticController.stop;
double lastDelta = 0; double lastDelta = 0;
void _tick() { void _tick() {
final double delta = ballisticController.value - lastDelta; final double delta = ballisticController.value - lastDelta;
...@@ -501,7 +513,10 @@ class _DraggableScrollableSheetScrollPosition ...@@ -501,7 +513,10 @@ class _DraggableScrollableSheetScrollPosition
ballisticController ballisticController
..addListener(_tick) ..addListener(_tick)
..animateWith(simulation).whenCompleteOrCancel( ..animateWith(simulation).whenCompleteOrCancel(
ballisticController.dispose, () {
_ballisticCancelCallback = null;
ballisticController.dispose();
},
); );
} }
......
...@@ -264,6 +264,40 @@ void main() { ...@@ -264,6 +264,40 @@ void main() {
expect(find.text('Item 70'), findsNothing); expect(find.text('Item 70'), findsNothing);
}, variant: TargetPlatformVariant.all()); }, variant: TargetPlatformVariant.all());
testWidgets('Ballistic animation on fling can be interrupted', (WidgetTester tester) async {
int taps = 0;
await tester.pumpWidget(_boilerplate(() => taps++));
expect(find.text('TapHere'), findsOneWidget);
await tester.tap(find.text('TapHere'));
expect(taps, 1);
expect(find.text('Item 1'), findsOneWidget);
expect(find.text('Item 31'), findsNothing);
expect(find.text('Item 70'), findsNothing);
await tester.fling(find.text('Item 1'), const Offset(0, -200), 2000);
// Don't pump and settle because we want to interrupt the ballistic scrolling animation.
expect(find.text('TapHere'), findsOneWidget);
await tester.tap(find.text('TapHere'), warnIfMissed: false);
expect(taps, 2);
expect(find.text('Item 1'), findsOneWidget);
expect(find.text('Item 31'), findsOneWidget);
expect(find.text('Item 70'), findsNothing);
// Use `dragFrom` here because calling `drag` on a list item without
// first calling `pumpAndSettle` fails with a hit test error.
await tester.dragFrom(const Offset(0, 200), const Offset(0, 200));
await tester.pumpAndSettle();
// Verify that the ballistic animation has canceled and the sheet has
// returned to it's original position.
await tester.tap(find.text('TapHere'));
expect(taps, 3);
expect(find.text('Item 1'), findsOneWidget);
expect(find.text('Item 31'), findsNothing);
expect(find.text('Item 70'), findsNothing);
}, variant: TargetPlatformVariant.all());
debugDefaultTargetPlatformOverride = null; debugDefaultTargetPlatformOverride = null;
}); });
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment