diff --git a/packages/flutter/lib/src/cupertino/refresh.dart b/packages/flutter/lib/src/cupertino/refresh.dart index 6a1df7a994d..1a22775a92e 100644 --- a/packages/flutter/lib/src/cupertino/refresh.dart +++ b/packages/flutter/lib/src/cupertino/refresh.dart @@ -520,7 +520,7 @@ class _CupertinoSliverRefreshControlState extends State 0) { return widget.builder( context, refreshState, diff --git a/packages/flutter/test/cupertino/refresh_test.dart b/packages/flutter/test/cupertino/refresh_test.dart index 1a032182e09..fff138f6dcd 100644 --- a/packages/flutter/test/cupertino/refresh_test.dart +++ b/packages/flutter/test/cupertino/refresh_test.dart @@ -38,16 +38,9 @@ void main() { when(mockHelper.builder( any, any, any, any, any)) .thenAnswer((Invocation i) { - final RefreshIndicatorMode refreshState = i.positionalArguments[1]; final double pulledExtent = i.positionalArguments[2]; final double refreshTriggerPullDistance = i.positionalArguments[3]; final double refreshIndicatorExtent = i.positionalArguments[4]; - if (refreshState == RefreshIndicatorMode.inactive) { - throw TestFailure( - 'RefreshControlIndicatorBuilder should never be called with the ' - "inactive state because there's nothing to build in that case" - ); - } if (pulledExtent < 0.0) { throw TestFailure('The pulledExtent should never be less than 0.0'); } @@ -535,6 +528,94 @@ void main() { debugDefaultTargetPlatformOverride = null; }); + testWidgets('builder still called when sliver snapped back more than 90%', (WidgetTester tester) async { + debugDefaultTargetPlatformOverride = TargetPlatform.iOS; + + refreshIndicator = const Center(child: Text('-1')); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: CustomScrollView( + slivers: [ + CupertinoSliverRefreshControl( + builder: builder, + onRefresh: onRefresh, + ), + buildAListOfStuff(), + ], + ), + ), + ); + + await tester.drag(find.text('0'), const Offset(0.0, 150.0)); + await tester.pump(); + verify(mockHelper.builder( + any, + RefreshIndicatorMode.armed, + 150.0, + 100.0, // Default value. + 60.0, // Default value. + )); + expect( + tester.getRect(find.widgetWithText(Center, '-1')), + Rect.fromLTRB(0.0, 0.0, 800.0, 150.0), + ); + verify(mockHelper.refreshTask()); + + // Rebuilds the sliver with a layout extent now. + await tester.pump(); + // Let it snap back to occupy the indicator's final sliver space only. + await tester.pump(const Duration(seconds: 2)); + verify(mockHelper.builder( + any, + RefreshIndicatorMode.refresh, + 60.0, + 100.0, // Default value. + 60.0, // Default value. + )); + expect( + tester.getRect(find.widgetWithText(Center, '-1')), + Rect.fromLTRB(0.0, 0.0, 800.0, 60.0), + ); + expect( + tester.getRect(find.widgetWithText(Center, '0')), + Rect.fromLTRB(0.0, 60.0, 800.0, 260.0), + ); + + refreshCompleter.complete(null); + await tester.pump(); + verify(mockHelper.builder( + any, + RefreshIndicatorMode.done, + 60.0, + 100.0, // Default value. + 60.0, // Default value. + )); + + // Waiting for refresh control to reach approximately 5% of height + await tester.pump(const Duration(milliseconds: 400)); + + expect( + tester.getRect(find.widgetWithText(Center, '0')).top, + moreOrLessEquals(3.0, epsilon: 4e-1), + ); + expect( + tester.getRect(find.widgetWithText(Center, '-1')).height, + moreOrLessEquals(3.0, epsilon: 4e-1), + ); + verify(mockHelper.builder( + any, + RefreshIndicatorMode.inactive, + 2.6980688300546443, // ~5% of 60.0 + 100.0, // Default value. + 60.0, // Default value. + )); + expect(find.text('-1'), findsOneWidget); + + debugDefaultTargetPlatformOverride = null; + }); + testWidgets( 'retracting sliver during done cannot be pulled to refresh again until fully retracted', (WidgetTester tester) async {