Skip to content

Commit 1c43399

Browse files
authored
Fix disallowIndicator for RefreshIndicator (#106831)
1 parent 49a52ae commit 1c43399

File tree

3 files changed

+120
-8
lines changed

3 files changed

+120
-8
lines changed

packages/flutter/lib/src/material/refresh_indicator.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -383,12 +383,12 @@ class RefreshIndicatorState extends State<RefreshIndicator> with TickerProviderS
383383
return false;
384384
}
385385

386-
bool _handleGlowNotification(OverscrollIndicatorNotification notification) {
386+
bool _handleIndicatorNotification(OverscrollIndicatorNotification notification) {
387387
if (notification.depth != 0 || !notification.leading) {
388388
return false;
389389
}
390390
if (_mode == _RefreshIndicatorMode.drag) {
391-
notification.disallowGlow();
391+
notification.disallowIndicator();
392392
return true;
393393
}
394394
return false;
@@ -535,7 +535,7 @@ class RefreshIndicatorState extends State<RefreshIndicator> with TickerProviderS
535535
final Widget child = NotificationListener<ScrollNotification>(
536536
onNotification: _handleScrollNotification,
537537
child: NotificationListener<OverscrollIndicatorNotification>(
538-
onNotification: _handleGlowNotification,
538+
onNotification: _handleIndicatorNotification,
539539
child: widget.child,
540540
),
541541
);

packages/flutter/lib/src/widgets/overscroll_indicator.dart

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ class _GlowingOverscrollIndicatorState extends State<GlowingOverscrollIndicator>
234234
if (_lastNotificationType is! OverscrollNotification) {
235235
final OverscrollIndicatorNotification confirmationNotification = OverscrollIndicatorNotification(leading: isLeading);
236236
confirmationNotification.dispatch(context);
237-
_accepted[isLeading] = confirmationNotification._accepted;
237+
_accepted[isLeading] = confirmationNotification.accepted;
238238
if (_accepted[isLeading]!) {
239239
controller!._paintOffset = confirmationNotification.paintOffset;
240240
}
@@ -714,7 +714,7 @@ class _StretchingOverscrollIndicatorState extends State<StretchingOverscrollIndi
714714
if (_lastNotification.runtimeType is! OverscrollNotification) {
715715
final OverscrollIndicatorNotification confirmationNotification = OverscrollIndicatorNotification(leading: notification.overscroll < 0.0);
716716
confirmationNotification.dispatch(context);
717-
_accepted = confirmationNotification._accepted;
717+
_accepted = confirmationNotification.accepted;
718718
}
719719

720720
assert(notification.metrics.axis == widget.axis);
@@ -978,7 +978,16 @@ class OverscrollIndicatorNotification extends Notification with ViewportNotifica
978978
/// This has no effect on a [StretchingOverscrollIndicator].
979979
double paintOffset = 0.0;
980980

981-
bool _accepted = true;
981+
@protected
982+
@visibleForTesting
983+
/// Whether the current overscroll event will allow for the indicator to be
984+
/// shown.
985+
///
986+
/// Calling [disallowIndicator] sets this to false, preventing the over scroll
987+
/// indicator from showing.
988+
///
989+
/// Defaults to true, cannot be null.
990+
bool accepted = true;
982991

983992
/// Call this method if the glow should be prevented. This method is
984993
/// deprecated in favor of [disallowIndicator].
@@ -987,12 +996,12 @@ class OverscrollIndicatorNotification extends Notification with ViewportNotifica
987996
'This feature was deprecated after v2.5.0-6.0.pre.',
988997
)
989998
void disallowGlow() {
990-
_accepted = false;
999+
accepted = false;
9911000
}
9921001

9931002
/// Call this method if the overscroll indicator should be prevented.
9941003
void disallowIndicator() {
995-
_accepted = false;
1004+
accepted = false;
9961005
}
9971006

9981007
@override

packages/flutter/test/material/refresh_indicator_test.dart

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -902,4 +902,107 @@ void main() {
902902
await tester.pump(const Duration(seconds: 1)); // finish the indicator hide animation
903903
expect(refreshCalled, true);
904904
});
905+
906+
testWidgets('RefreshIndicator disallows indicator - glow', (WidgetTester tester) async {
907+
refreshCalled = false;
908+
bool glowAccepted = true;
909+
ScrollNotification? lastNotification;
910+
911+
await tester.pumpWidget(
912+
MaterialApp(
913+
home: RefreshIndicator(
914+
onRefresh: refresh,
915+
child: Builder(
916+
builder: (BuildContext context) {
917+
return NotificationListener<ScrollNotification>(
918+
onNotification: (ScrollNotification notification) {
919+
if (notification is OverscrollNotification
920+
&& lastNotification is! OverscrollNotification) {
921+
final OverscrollIndicatorNotification confirmationNotification = OverscrollIndicatorNotification(leading: true);
922+
confirmationNotification.dispatch(context);
923+
glowAccepted = confirmationNotification.accepted;
924+
}
925+
lastNotification = notification;
926+
return false;
927+
},
928+
child: ListView(
929+
physics: const AlwaysScrollableScrollPhysics(),
930+
children: <String>['A', 'B', 'C', 'D', 'E', 'F'].map<Widget>((String item) {
931+
return SizedBox(
932+
height: 200.0,
933+
child: Text(item),
934+
);
935+
}).toList(),
936+
),
937+
);
938+
}
939+
),
940+
),
941+
),
942+
);
943+
944+
expect(find.byType(StretchingOverscrollIndicator), findsNothing);
945+
expect(find.byType(GlowingOverscrollIndicator), findsOneWidget);
946+
947+
await tester.fling(find.text('A'), const Offset(0.0, 300.0), 1000.0);
948+
await tester.pump();
949+
950+
await tester.pump(const Duration(seconds: 1)); // finish the scroll animation
951+
await tester.pump(const Duration(seconds: 1)); // finish the indicator settle animation
952+
await tester.pump(const Duration(seconds: 1)); // finish the indicator hide animation
953+
expect(refreshCalled, true);
954+
expect(glowAccepted, false);
955+
});
956+
957+
testWidgets('RefreshIndicator disallows indicator - stretch', (WidgetTester tester) async {
958+
refreshCalled = false;
959+
bool stretchAccepted = true;
960+
ScrollNotification? lastNotification;
961+
962+
await tester.pumpWidget(
963+
MaterialApp(
964+
theme: ThemeData.light().copyWith(useMaterial3: true),
965+
home: RefreshIndicator(
966+
onRefresh: refresh,
967+
child: Builder(
968+
builder: (BuildContext context) {
969+
return NotificationListener<ScrollNotification>(
970+
onNotification: (ScrollNotification notification) {
971+
if (notification is OverscrollNotification
972+
&& lastNotification is! OverscrollNotification) {
973+
final OverscrollIndicatorNotification confirmationNotification = OverscrollIndicatorNotification(leading: true);
974+
confirmationNotification.dispatch(context);
975+
stretchAccepted = confirmationNotification.accepted;
976+
}
977+
lastNotification = notification;
978+
return false;
979+
},
980+
child: ListView(
981+
physics: const AlwaysScrollableScrollPhysics(),
982+
children: <String>['A', 'B', 'C', 'D', 'E', 'F'].map<Widget>((String item) {
983+
return SizedBox(
984+
height: 200.0,
985+
child: Text(item),
986+
);
987+
}).toList(),
988+
),
989+
);
990+
}
991+
),
992+
),
993+
),
994+
);
995+
996+
expect(find.byType(StretchingOverscrollIndicator), findsOneWidget);
997+
expect(find.byType(GlowingOverscrollIndicator), findsNothing);
998+
999+
await tester.fling(find.text('A'), const Offset(0.0, 300.0), 1000.0);
1000+
await tester.pump();
1001+
1002+
await tester.pump(const Duration(seconds: 1)); // finish the scroll animation
1003+
await tester.pump(const Duration(seconds: 1)); // finish the indicator settle animation
1004+
await tester.pump(const Duration(seconds: 1)); // finish the indicator hide animation
1005+
expect(refreshCalled, true);
1006+
expect(stretchAccepted, false);
1007+
});
9051008
}

0 commit comments

Comments
 (0)