mirror of
https://github.com/flutter/flutter
synced 2024-10-13 03:32:55 +00:00
Cancel DraggableScrollableSheet ballistic animation if a new activity begins (#86614)
This commit is contained in:
parent
3d47dd851d
commit
4ab29de67f
|
@ -10,6 +10,7 @@ import 'framework.dart';
|
|||
import 'inherited_notifier.dart';
|
||||
import 'layout_builder.dart';
|
||||
import 'notification_listener.dart';
|
||||
import 'scroll_activity.dart';
|
||||
import 'scroll_context.dart';
|
||||
import 'scroll_controller.dart';
|
||||
import 'scroll_notification.dart';
|
||||
|
@ -431,9 +432,17 @@ class _DraggableScrollableSheetScrollPosition
|
|||
);
|
||||
|
||||
VoidCallback? _dragCancelCallback;
|
||||
VoidCallback? _ballisticCancelCallback;
|
||||
final _DraggableSheetExtent extent;
|
||||
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
|
||||
bool applyContentDimensions(double minScrollExtent, double maxScrollExtent) {
|
||||
// We need to provide some extra extent if we haven't yet reached the max or
|
||||
|
@ -481,6 +490,9 @@ class _DraggableScrollableSheetScrollPosition
|
|||
debugLabel: objectRuntimeType(this, '_DraggableScrollableSheetPosition'),
|
||||
vsync: context.vsync,
|
||||
);
|
||||
// Stop the ballistic animation if a new activity starts.
|
||||
// See: [beginActivity].
|
||||
_ballisticCancelCallback = ballisticController.stop;
|
||||
double lastDelta = 0;
|
||||
void _tick() {
|
||||
final double delta = ballisticController.value - lastDelta;
|
||||
|
@ -501,7 +513,10 @@ class _DraggableScrollableSheetScrollPosition
|
|||
ballisticController
|
||||
..addListener(_tick)
|
||||
..animateWith(simulation).whenCompleteOrCancel(
|
||||
ballisticController.dispose,
|
||||
() {
|
||||
_ballisticCancelCallback = null;
|
||||
ballisticController.dispose();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -264,6 +264,40 @@ void main() {
|
|||
expect(find.text('Item 70'), findsNothing);
|
||||
}, 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;
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in a new issue