Fix PageController throws when changing page before viewPortDimensions are set (#153017)

## Description

This PR fixes `PageController` throwing when using `jumpToPage` or `animateToPage` to switch page before the viewport dimensions were retrieved.

Solution based on https://github.com/flutter/flutter/pull/152947#discussion_r1706203170.

## Related Issue

Fixes https://github.com/flutter/flutter/issues/86222.
Fixes https://github.com/flutter/flutter/issues/152079

## Tests

Adds 2 tests.
This commit is contained in:
Bruno Leroux 2024-08-07 18:45:53 +02:00 committed by GitHub
parent 2ff7fe92c1
commit d595e98d85
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 68 additions and 0 deletions

View File

@ -200,6 +200,11 @@ class PageController extends ScrollController {
return Future<void>.value();
}
if (!position.hasViewportDimension) {
position._pageToUseOnStartup = page.toDouble();
return Future<void>.value();
}
return position.animateTo(
position.getPixelsFromPage(page.toDouble()),
duration: duration,
@ -218,6 +223,11 @@ class PageController extends ScrollController {
return;
}
if (!position.hasViewportDimension) {
position._pageToUseOnStartup = page.toDouble();
return;
}
position.jumpTo(position.getPixelsFromPage(page.toDouble()));
}

View File

@ -1413,4 +1413,62 @@ void main() {
expect(find.text('null'), findsNothing);
expect(currentPage, 'not empty');
});
testWidgets('Does not crash when calling jumpToPage before layout', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/86222.
final PageController controller = PageController();
addTearDown(controller.dispose);
await tester.pumpWidget(MaterialApp(
home: Scaffold(
body: Navigator(
onDidRemovePage: (Page<Object?> page) {},
pages: <Page<void>>[
MaterialPage<void>(child: Scaffold(
body: PageView(
controller: controller,
children: const <Widget>[
Scaffold(body: Text('One')),
Scaffold(body: Text('Two')),
],
),
)),
const MaterialPage<void>(child: Scaffold()),
],
),
)
));
controller.jumpToPage(1);
expect(tester.takeException(), null);
});
testWidgets('Does not crash when calling animateToPage before layout', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/86222.
final PageController controller = PageController();
addTearDown(controller.dispose);
await tester.pumpWidget(MaterialApp(
home: Scaffold(
body: Navigator(
onDidRemovePage: (Page<Object?> page) {},
pages: <Page<void>>[
MaterialPage<void>(child: Scaffold(
body: PageView(
controller: controller,
children: const <Widget>[
Scaffold(body: Text('One')),
Scaffold(body: Text('Two')),
],
),
)),
const MaterialPage<void>(child: Scaffold()),
],
),
)
));
controller.animateToPage(1, duration: const Duration(milliseconds: 50), curve: Curves.bounceIn);
expect(tester.takeException(), null);
});
}