Fix the NestedScrollView exception when rebuilding during scheduleWarmUpFrame (#75308)
diff --git a/packages/flutter/lib/src/widgets/nested_scroll_view.dart b/packages/flutter/lib/src/widgets/nested_scroll_view.dart
index 5324dbe..7a63d6b 100644
--- a/packages/flutter/lib/src/widgets/nested_scroll_view.dart
+++ b/packages/flutter/lib/src/widgets/nested_scroll_view.dart
@@ -795,8 +795,13 @@
bool get hasScrolledBody {
for (final _NestedScrollPosition position in _innerPositions) {
- assert(position.hasContentDimensions && position.hasPixels);
- if (position.pixels > position.minScrollExtent) {
+ if (!position.hasContentDimensions || !position.hasPixels) {
+ // It's possible that NestedScrollView built twice before layout phase
+ // in the same frame. This can happen when the FocusManager schedules a microTask
+ // that marks NestedScrollView dirty during the warm up frame.
+ // https://github.com/flutter/flutter/pull/75308
+ continue;
+ } else if (position.pixels > position.minScrollExtent) {
return true;
}
}
diff --git a/packages/flutter/test/widgets/nested_scroll_view_test.dart b/packages/flutter/test/widgets/nested_scroll_view_test.dart
index c55a307..3bbdf86 100644
--- a/packages/flutter/test/widgets/nested_scroll_view_test.dart
+++ b/packages/flutter/test/widgets/nested_scroll_view_test.dart
@@ -2303,6 +2303,49 @@
expect(lastUserScrollingDirection, ScrollDirection.forward);
});
+
+ // Regression test for https://github.com/flutter/flutter/issues/72257
+ testWidgets('NestedScrollView works well when rebuilding during scheduleWarmUpFrame', (WidgetTester tester) async {
+ bool? isScrolled;
+ final Widget myApp = MaterialApp(
+ home: Scaffold(
+ body: StatefulBuilder(
+ builder: (BuildContext context, StateSetter setState) {
+ return Focus(
+ onFocusChange: (_) => setState( (){} ),
+ child: NestedScrollView(
+ headerSliverBuilder: (BuildContext context, bool boxIsScrolled) {
+ isScrolled = boxIsScrolled;
+ return <Widget>[
+ const SliverAppBar(
+ expandedHeight: 200,
+ title: Text('Test'),
+ )
+ ];
+ },
+ body: CustomScrollView(
+ slivers: <Widget>[
+ SliverList(
+ delegate: SliverChildBuilderDelegate(
+ (BuildContext context, int index) {
+ return const Text('');
+ },
+ childCount: 10,
+ ),
+ )
+ ],
+ ),
+ ),
+ );
+ },
+ ),
+ ),
+ );
+
+ await tester.pumpWidget(myApp, Duration.zero, EnginePhase.build);
+ expect(isScrolled, false);
+ expect(tester.takeException(), isNull);
+ });
}
class TestHeader extends SliverPersistentHeaderDelegate {