Skip to content

Commit 27394f6

Browse files
authored
Fix sliver persistent header expand animation (#137913)
Added animation status check at showOnScreen method to prevent broken animation of expanding SliverAppBar when focusing EditableText close #137901
1 parent 4d788b1 commit 27394f6

File tree

2 files changed

+41
-1
lines changed

2 files changed

+41
-1
lines changed

packages/flutter/lib/src/rendering/sliver_persistent_header.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -741,7 +741,7 @@ abstract class RenderSliverFloatingPersistentHeader extends RenderSliverPersiste
741741
effectiveMaxExtent);
742742

743743
// Expands the header if needed, with animation.
744-
if (targetExtent > childExtent) {
744+
if (targetExtent > childExtent && _controller?.status != AnimationStatus.forward) {
745745
final double targetScrollOffset = maxExtent - targetExtent;
746746
assert(
747747
vsync != null,

packages/flutter/test/rendering/viewport_test.dart

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1314,6 +1314,46 @@ void main() {
13141314
},
13151315
);
13161316

1317+
testWidgetsWithLeakTracking('RenderViewportBase.showOnScreen twice almost instantly', (WidgetTester tester) async{
1318+
// Regression test for https://github.com/flutter/flutter/issues/137901
1319+
await tester.pumpWidget(
1320+
buildList(
1321+
floatingHeader: SliverPersistentHeader(
1322+
pinned: true,
1323+
floating: true,
1324+
delegate: _TestSliverPersistentHeaderDelegate(minExtent: 100, maxExtent: 300, key: headerKey, vsync: vsync),
1325+
),
1326+
),
1327+
);
1328+
1329+
final Finder pinnedHeaderContent = find.byKey(headerKey, skipOffstage: false);
1330+
1331+
controller.jumpTo(300.0 * 15);
1332+
await tester.pumpAndSettle();
1333+
expect(mainAxisExtent(tester, pinnedHeaderContent), lessThan(300));
1334+
1335+
1336+
tester.renderObject(pinnedHeaderContent).showOnScreen(
1337+
descendant: tester.renderObject(pinnedHeaderContent),
1338+
// Adding different rect to check if the second showOnScreen call
1339+
// leads to a different result.
1340+
// When the animation has forward status and the second showOnScreen
1341+
// is called, the new animation won't start.
1342+
rect: Offset.zero & const Size(150, 150),
1343+
duration: const Duration(seconds: 3),
1344+
);
1345+
await tester.pump(const Duration(seconds: 1));
1346+
1347+
tester.renderObject(pinnedHeaderContent).showOnScreen(
1348+
descendant: tester.renderObject(pinnedHeaderContent),
1349+
rect: Offset.zero & const Size(300, 300),
1350+
);
1351+
1352+
await tester.pumpAndSettle();
1353+
expect(controller.offset, 300.0 * 15);
1354+
expect(mainAxisExtent(tester, pinnedHeaderContent), 150);
1355+
});
1356+
13171357
testWidgetsWithLeakTracking(
13181358
'RenderViewportBase.showOnScreen but no child',
13191359
(WidgetTester tester) async {

0 commit comments

Comments
 (0)