Skip to content

Commit 16af4aa

Browse files
authored
Fix the NestedScrollView exception when rebuilding during scheduleWarmUpFrame (flutter#75308)
1 parent 6ad9f78 commit 16af4aa

File tree

2 files changed

+50
-2
lines changed

2 files changed

+50
-2
lines changed

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -795,8 +795,13 @@ class _NestedScrollCoordinator implements ScrollActivityDelegate, ScrollHoldCont
795795

796796
bool get hasScrolledBody {
797797
for (final _NestedScrollPosition position in _innerPositions) {
798-
assert(position.hasContentDimensions && position.hasPixels);
799-
if (position.pixels > position.minScrollExtent) {
798+
if (!position.hasContentDimensions || !position.hasPixels) {
799+
// It's possible that NestedScrollView built twice before layout phase
800+
// in the same frame. This can happen when the FocusManager schedules a microTask
801+
// that marks NestedScrollView dirty during the warm up frame.
802+
// https://github.com/flutter/flutter/pull/75308
803+
continue;
804+
} else if (position.pixels > position.minScrollExtent) {
800805
return true;
801806
}
802807
}

packages/flutter/test/widgets/nested_scroll_view_test.dart

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2303,6 +2303,49 @@ void main() {
23032303

23042304
expect(lastUserScrollingDirection, ScrollDirection.forward);
23052305
});
2306+
2307+
// Regression test for https://github.com/flutter/flutter/issues/72257
2308+
testWidgets('NestedScrollView works well when rebuilding during scheduleWarmUpFrame', (WidgetTester tester) async {
2309+
bool? isScrolled;
2310+
final Widget myApp = MaterialApp(
2311+
home: Scaffold(
2312+
body: StatefulBuilder(
2313+
builder: (BuildContext context, StateSetter setState) {
2314+
return Focus(
2315+
onFocusChange: (_) => setState( (){} ),
2316+
child: NestedScrollView(
2317+
headerSliverBuilder: (BuildContext context, bool boxIsScrolled) {
2318+
isScrolled = boxIsScrolled;
2319+
return <Widget>[
2320+
const SliverAppBar(
2321+
expandedHeight: 200,
2322+
title: Text('Test'),
2323+
)
2324+
];
2325+
},
2326+
body: CustomScrollView(
2327+
slivers: <Widget>[
2328+
SliverList(
2329+
delegate: SliverChildBuilderDelegate(
2330+
(BuildContext context, int index) {
2331+
return const Text('');
2332+
},
2333+
childCount: 10,
2334+
),
2335+
)
2336+
],
2337+
),
2338+
),
2339+
);
2340+
},
2341+
),
2342+
),
2343+
);
2344+
2345+
await tester.pumpWidget(myApp, Duration.zero, EnginePhase.build);
2346+
expect(isScrolled, false);
2347+
expect(tester.takeException(), isNull);
2348+
});
23062349
}
23072350

23082351
class TestHeader extends SliverPersistentHeaderDelegate {

0 commit comments

Comments
 (0)