Report progress on Dismissible update callback (#95504)
diff --git a/packages/flutter/lib/src/widgets/dismissible.dart b/packages/flutter/lib/src/widgets/dismissible.dart
index 0a58d93..9210c4d 100644
--- a/packages/flutter/lib/src/widgets/dismissible.dart
+++ b/packages/flutter/lib/src/widgets/dismissible.dart
@@ -233,7 +233,8 @@
DismissUpdateDetails({
this.direction = DismissDirection.horizontal,
this.reached = false,
- this.previousReached = false
+ this.previousReached = false,
+ this.progress = 0.0,
});
/// The direction that the dismissible is being dragged.
@@ -247,6 +248,15 @@
/// This can be used in conjunction with [DismissUpdateDetails.reached] to catch the moment
/// that the [Dismissible] is dragged across the threshold.
final bool previousReached;
+
+ /// The offset ratio of the dismissible in its parent container.
+ ///
+ /// A value of 0.0 represents the normal position and 1.0 means the child is
+ /// completely outside its parent.
+ ///
+ /// This can be used to synchronize other elements to what the dismissible is doing on screen,
+ /// e.g. using this value to set the opacity thereby fading dismissible as it's dragged offscreen.
+ final double progress;
}
class _DismissibleClipper extends CustomClipper<Rect> {
@@ -438,6 +448,7 @@
direction: _dismissDirection,
reached: _dismissThresholdReached,
previousReached: oldDismissThresholdReached,
+ progress: _moveController!.value,
);
widget.onUpdate!(details);
}
diff --git a/packages/flutter/test/widgets/dismissible_test.dart b/packages/flutter/test/widgets/dismissible_test.dart
index c8b3511..0b807d8 100644
--- a/packages/flutter/test/widgets/dismissible_test.dart
+++ b/packages/flutter/test/widgets/dismissible_test.dart
@@ -12,6 +12,7 @@
const double crossAxisEndOffset = 0.5;
bool reportedDismissUpdateReached = false;
bool reportedDismissUpdatePreviousReached = false;
+double reportedDismissUpdateProgress = 0.0;
late DismissDirection reportedDismissUpdateReachedDirection;
DismissDirection reportedDismissDirection = DismissDirection.horizontal;
@@ -53,6 +54,7 @@
reportedDismissUpdateReachedDirection = details.direction;
reportedDismissUpdateReached = details.reached;
reportedDismissUpdatePreviousReached = details.previousReached;
+ reportedDismissUpdateProgress = details.progress;
},
background: background,
dismissThresholds: startToEndThreshold == null
@@ -120,6 +122,25 @@
await gesture.up();
}
+Future<void> dragElement(WidgetTester tester, Finder finder, { required AxisDirection gestureDirection, required double amount }) async {
+ Offset delta;
+ switch (gestureDirection) {
+ case AxisDirection.left:
+ delta = Offset(-amount, 0.0);
+ break;
+ case AxisDirection.right:
+ delta = Offset(amount, 0.0);
+ break;
+ case AxisDirection.up:
+ delta = Offset(0.0, -amount);
+ break;
+ case AxisDirection.down:
+ delta = Offset(0.0, amount);
+ break;
+ }
+ await tester.drag(finder, delta);
+}
+
Future<void> flingElement(WidgetTester tester, Finder finder, { required AxisDirection gestureDirection, double initialOffsetFactor = 0.0 }) async {
Offset delta;
switch (gestureDirection) {
@@ -161,6 +182,20 @@
await tester.pumpAndSettle();
}
+Future<void> dragItem(
+ WidgetTester tester,
+ int item, {
+ required AxisDirection gestureDirection,
+ required double amount,
+ }) async {
+ assert(gestureDirection != null);
+ final Finder itemFinder = find.text(item.toString());
+ expect(itemFinder, findsOneWidget);
+
+ await dragElement(tester, itemFinder, gestureDirection: gestureDirection, amount: amount);
+ await tester.pump();
+}
+
Future<void> checkFlingItemBeforeMovementEnd(
WidgetTester tester,
int item, {
@@ -1068,6 +1103,10 @@
));
expect(dismissedItems, isEmpty);
+ // Unsuccessful dismiss, fractional progress reported
+ await dragItem(tester, 0, gestureDirection: AxisDirection.right, amount: 20);
+ expect(reportedDismissUpdateProgress, 0.2);
+
// Successful dismiss therefore threshold has been reached
await dismissItem(tester, 0, mechanism: flingElement, gestureDirection: AxisDirection.left);
expect(find.text('0'), findsNothing);
@@ -1075,6 +1114,7 @@
expect(reportedDismissUpdateReachedDirection, DismissDirection.endToStart);
expect(reportedDismissUpdateReached, true);
expect(reportedDismissUpdatePreviousReached, true);
+ expect(reportedDismissUpdateProgress, 1.0);
// Unsuccessful dismiss, threshold has not been reached
await checkFlingItemAfterMovement(tester, 1, gestureDirection: AxisDirection.right);
@@ -1083,6 +1123,7 @@
expect(reportedDismissUpdateReachedDirection, DismissDirection.startToEnd);
expect(reportedDismissUpdateReached, false);
expect(reportedDismissUpdatePreviousReached, false);
+ expect(reportedDismissUpdateProgress, 0.0);
// Another successful dismiss from another direction
await dismissItem(tester, 1, mechanism: flingElement, gestureDirection: AxisDirection.right);
@@ -1091,6 +1132,7 @@
expect(reportedDismissUpdateReachedDirection, DismissDirection.startToEnd);
expect(reportedDismissUpdateReached, true);
expect(reportedDismissUpdatePreviousReached, true);
+ expect(reportedDismissUpdateProgress, 1.0);
await tester.pumpWidget(buildTest(
scrollDirection: Axis.horizontal,
@@ -1106,5 +1148,6 @@
expect(reportedDismissUpdateReachedDirection, DismissDirection.startToEnd);
expect(reportedDismissUpdateReached, false);
expect(reportedDismissUpdatePreviousReached, false);
+ expect(reportedDismissUpdateProgress, 0.0);
});
}