forked from firka/flutter
Fix disallowIndicator for RefreshIndicator (#106831)
This commit is contained in:
@@ -383,12 +383,12 @@ class RefreshIndicatorState extends State<RefreshIndicator> with TickerProviderS
|
||||
return false;
|
||||
}
|
||||
|
||||
bool _handleGlowNotification(OverscrollIndicatorNotification notification) {
|
||||
bool _handleIndicatorNotification(OverscrollIndicatorNotification notification) {
|
||||
if (notification.depth != 0 || !notification.leading) {
|
||||
return false;
|
||||
}
|
||||
if (_mode == _RefreshIndicatorMode.drag) {
|
||||
notification.disallowGlow();
|
||||
notification.disallowIndicator();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -535,7 +535,7 @@ class RefreshIndicatorState extends State<RefreshIndicator> with TickerProviderS
|
||||
final Widget child = NotificationListener<ScrollNotification>(
|
||||
onNotification: _handleScrollNotification,
|
||||
child: NotificationListener<OverscrollIndicatorNotification>(
|
||||
onNotification: _handleGlowNotification,
|
||||
onNotification: _handleIndicatorNotification,
|
||||
child: widget.child,
|
||||
),
|
||||
);
|
||||
|
||||
@@ -234,7 +234,7 @@ class _GlowingOverscrollIndicatorState extends State<GlowingOverscrollIndicator>
|
||||
if (_lastNotificationType is! OverscrollNotification) {
|
||||
final OverscrollIndicatorNotification confirmationNotification = OverscrollIndicatorNotification(leading: isLeading);
|
||||
confirmationNotification.dispatch(context);
|
||||
_accepted[isLeading] = confirmationNotification._accepted;
|
||||
_accepted[isLeading] = confirmationNotification.accepted;
|
||||
if (_accepted[isLeading]!) {
|
||||
controller!._paintOffset = confirmationNotification.paintOffset;
|
||||
}
|
||||
@@ -714,7 +714,7 @@ class _StretchingOverscrollIndicatorState extends State<StretchingOverscrollIndi
|
||||
if (_lastNotification.runtimeType is! OverscrollNotification) {
|
||||
final OverscrollIndicatorNotification confirmationNotification = OverscrollIndicatorNotification(leading: notification.overscroll < 0.0);
|
||||
confirmationNotification.dispatch(context);
|
||||
_accepted = confirmationNotification._accepted;
|
||||
_accepted = confirmationNotification.accepted;
|
||||
}
|
||||
|
||||
assert(notification.metrics.axis == widget.axis);
|
||||
@@ -978,7 +978,16 @@ class OverscrollIndicatorNotification extends Notification with ViewportNotifica
|
||||
/// This has no effect on a [StretchingOverscrollIndicator].
|
||||
double paintOffset = 0.0;
|
||||
|
||||
bool _accepted = true;
|
||||
@protected
|
||||
@visibleForTesting
|
||||
/// Whether the current overscroll event will allow for the indicator to be
|
||||
/// shown.
|
||||
///
|
||||
/// Calling [disallowIndicator] sets this to false, preventing the over scroll
|
||||
/// indicator from showing.
|
||||
///
|
||||
/// Defaults to true, cannot be null.
|
||||
bool accepted = true;
|
||||
|
||||
/// Call this method if the glow should be prevented. This method is
|
||||
/// deprecated in favor of [disallowIndicator].
|
||||
@@ -987,12 +996,12 @@ class OverscrollIndicatorNotification extends Notification with ViewportNotifica
|
||||
'This feature was deprecated after v2.5.0-6.0.pre.',
|
||||
)
|
||||
void disallowGlow() {
|
||||
_accepted = false;
|
||||
accepted = false;
|
||||
}
|
||||
|
||||
/// Call this method if the overscroll indicator should be prevented.
|
||||
void disallowIndicator() {
|
||||
_accepted = false;
|
||||
accepted = false;
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -902,4 +902,107 @@ void main() {
|
||||
await tester.pump(const Duration(seconds: 1)); // finish the indicator hide animation
|
||||
expect(refreshCalled, true);
|
||||
});
|
||||
|
||||
testWidgets('RefreshIndicator disallows indicator - glow', (WidgetTester tester) async {
|
||||
refreshCalled = false;
|
||||
bool glowAccepted = true;
|
||||
ScrollNotification? lastNotification;
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: RefreshIndicator(
|
||||
onRefresh: refresh,
|
||||
child: Builder(
|
||||
builder: (BuildContext context) {
|
||||
return NotificationListener<ScrollNotification>(
|
||||
onNotification: (ScrollNotification notification) {
|
||||
if (notification is OverscrollNotification
|
||||
&& lastNotification is! OverscrollNotification) {
|
||||
final OverscrollIndicatorNotification confirmationNotification = OverscrollIndicatorNotification(leading: true);
|
||||
confirmationNotification.dispatch(context);
|
||||
glowAccepted = confirmationNotification.accepted;
|
||||
}
|
||||
lastNotification = notification;
|
||||
return false;
|
||||
},
|
||||
child: ListView(
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
children: <String>['A', 'B', 'C', 'D', 'E', 'F'].map<Widget>((String item) {
|
||||
return SizedBox(
|
||||
height: 200.0,
|
||||
child: Text(item),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
);
|
||||
}
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byType(StretchingOverscrollIndicator), findsNothing);
|
||||
expect(find.byType(GlowingOverscrollIndicator), findsOneWidget);
|
||||
|
||||
await tester.fling(find.text('A'), const Offset(0.0, 300.0), 1000.0);
|
||||
await tester.pump();
|
||||
|
||||
await tester.pump(const Duration(seconds: 1)); // finish the scroll animation
|
||||
await tester.pump(const Duration(seconds: 1)); // finish the indicator settle animation
|
||||
await tester.pump(const Duration(seconds: 1)); // finish the indicator hide animation
|
||||
expect(refreshCalled, true);
|
||||
expect(glowAccepted, false);
|
||||
});
|
||||
|
||||
testWidgets('RefreshIndicator disallows indicator - stretch', (WidgetTester tester) async {
|
||||
refreshCalled = false;
|
||||
bool stretchAccepted = true;
|
||||
ScrollNotification? lastNotification;
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeData.light().copyWith(useMaterial3: true),
|
||||
home: RefreshIndicator(
|
||||
onRefresh: refresh,
|
||||
child: Builder(
|
||||
builder: (BuildContext context) {
|
||||
return NotificationListener<ScrollNotification>(
|
||||
onNotification: (ScrollNotification notification) {
|
||||
if (notification is OverscrollNotification
|
||||
&& lastNotification is! OverscrollNotification) {
|
||||
final OverscrollIndicatorNotification confirmationNotification = OverscrollIndicatorNotification(leading: true);
|
||||
confirmationNotification.dispatch(context);
|
||||
stretchAccepted = confirmationNotification.accepted;
|
||||
}
|
||||
lastNotification = notification;
|
||||
return false;
|
||||
},
|
||||
child: ListView(
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
children: <String>['A', 'B', 'C', 'D', 'E', 'F'].map<Widget>((String item) {
|
||||
return SizedBox(
|
||||
height: 200.0,
|
||||
child: Text(item),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
);
|
||||
}
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byType(StretchingOverscrollIndicator), findsOneWidget);
|
||||
expect(find.byType(GlowingOverscrollIndicator), findsNothing);
|
||||
|
||||
await tester.fling(find.text('A'), const Offset(0.0, 300.0), 1000.0);
|
||||
await tester.pump();
|
||||
|
||||
await tester.pump(const Duration(seconds: 1)); // finish the scroll animation
|
||||
await tester.pump(const Duration(seconds: 1)); // finish the indicator settle animation
|
||||
await tester.pump(const Duration(seconds: 1)); // finish the indicator hide animation
|
||||
expect(refreshCalled, true);
|
||||
expect(stretchAccepted, false);
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user