From bd77b06968f54d9c2c0be15c7d43b64c0ea15a4a Mon Sep 17 00:00:00 2001 From: Justin McCandless Date: Tue, 15 Jul 2025 11:56:36 -0700 Subject: [PATCH 1/3] Template --- .../default-android-page-transition.md | 196 ++++++++++++++++++ src/content/release/breaking-changes/index.md | 2 + 2 files changed, 198 insertions(+) create mode 100644 src/content/release/breaking-changes/default-android-page-transition.md diff --git a/src/content/release/breaking-changes/default-android-page-transition.md b/src/content/release/breaking-changes/default-android-page-transition.md new file mode 100644 index 00000000000..e1b13890d46 --- /dev/null +++ b/src/content/release/breaking-changes/default-android-page-transition.md @@ -0,0 +1,196 @@ +--- +title: Replace with title of breaking change +description: Brief description similar to the "context" section below. The description shouldn't have any linebreaks - let it go long and wrap. Text below should break at 80 chars or less. +--- + +{% comment %} + PLEASE READ THESE GENERAL INSTRUCTIONS: + * All lines of text should be 80 chars OR LESS. + The writers strongly prefer semantic line breaks: + https://github.com/dart-lang/site-shared/blob/master/doc/writing-for-dart-and-flutter-websites.md#semantic-line-breaks + * DON'T SUBMIT a PR weeks and weeks in advance. + Doing this causes it to get stanky in the website + repo and usually develops conflicts in the index file. + Ideally, submit a PR once you have confirmed + info on the version number where the breaking + change landed. + * One of the most important things to fill out + in this template is the *Timeline* section. + I won't approve/merge the PR until the "landed in" + release info is provided. For example: + `Landed in version: 1.21.0-5.0.pre
`. + Do NOT list the PR in this section. Also, don't + fill in the "stable" release info unless it's + already in a published stable release. + After a stable release, I go through and confirm + that updates have made it to stable and I then + update the breaking change and the index file. + * The text in this page should be backwards looking, + so write about previous behavior in past tense, + not future tense. People are reading this months + from now when the change is likely in the stable + release, not today. Don't say "in a month" or + talk about your plan to do something next week. + Assume you've done it, and that they're looking + back to figure out how to migrate their code. + * Use sentence case for headings and titles. + (`## Migration guide`, NOT `Migration Guide`) + * DON'T use the abbreviation `i.e.` or `e.g.`. + Use "for example" or "such as", and similar. + * For links, use the macros where possible. + See the examples at the end of this template, + but don't use "github.com" or "api.flutter.dev" or + "pub.dev" in your URLs. Use the {{site.github}}, + {{site.api}}, or {{site.pub}} macros. + * AVOID "will" when possible, in other words, + stay in the present tense. For example: + Bad: "When encountering an xxx value, + the code will throw an exception." + Good: "When encountering an xxx value, + the code throws an exception." + Good use of "will": "In release 2.0, the xxx API + will be deprecated." + * If your included Dart code won't pass analysis + on its own (using the analyzer from the latest + stable release), then preface that code with an + HTML `` tag. + * Finally, delete the comment tags and text from the + final PR. +{% endcomment %} + +## Summary + +{% comment %} + A brief (one- to three-line) summary that gives + context as to what changed so that someone can + find it when browsing through an index of + breaking changes, ideally using keywords from + the symptoms you would see if you had not yet + migrated (for example, the text from probable + error messages). +{% endcomment %} + +## Context + +{% comment %} + High-level description of what API changed and why. + Should be clear enough to be understandable to someone + who has no context about this breaking change, + such as someone who doesn't know the underlying API. + This section should also answer the question + "what is the problem that led to considering making + a breaking change?" +{% endcomment %} + +## Description of change + +{% comment %} +A technical description of the actual change, +with code samples showing how the API changed. + +Include examples of the error messages that are produced +in code that has not been migrated. This helps the search +engine find the migration guide when people search for those +error messages. +{% endcomment %} + +## Migration guide + +{% comment %} + A description of how to make the change. + If a migration tool is available, + discuss it here. Even if there is a tool, + a description of how to make the change manually + must be provided. This section needs before and + after code examples that are relevant to the + developer. +{% endcomment %} + +Code before migration: + + +```dart +// Example of code before the change. +``` + +Code after migration: + + +```dart +// Example of code after the change. +``` + +## Timeline + +{% comment %} + The version # of the SDK where this change was + introduced. If there is a deprecation window, + the version # to which we guarantee to maintain + the old API. Use the following template: + + If a breaking change has been reverted in a + subsequent release, move that item to the + "Reverted" section of the index.md file. + Also add the "Reverted in version" line, + shown as optional below. Otherwise, delete + that line. +{% endcomment %} + +Landed in version: xxx
+In stable release: not yet +Reverted in version: xxx (OPTIONAL, delete if not used) + +## References + +{% comment %} + These links are commented out because they + cause the GitHubActions (GHA) linkcheck to fail. + Remove the comment tags once you fill this in with + real links. Only use the "master-api" include if + you link to "master-api.flutter.dev". + +{% include master-api.md %} + +API documentation: + +* [`ClassName`][] + +Relevant issues: + +* [Issue xxxx][] +* [Issue yyyy][] + +Relevant PRs: + +* [PR title #1][] +* [PR title #2][] +{% endcomment %} + +{% comment %} + Add the links to the end of the file in alphabetical order. + The following links are commented out because they make + the GitHubActions (GHA) link checker believe they are broken links, + but please remove the comment tags before you commit! + + If you are sharing new API that hasn't landed in + the stable channel yet, use the master channel link. + To link to docs on the master channel, + include the following note and make sure that + the URL includes the master link (as shown below). + + Here's an example of defining a stable (site.api) link + and a master channel (master-api) link. + + +[`ClassName`]: {{site.api}}/flutter/[link_to_relevant_page].html + + +{% include master-api.md %} + +[`ClassName`]: https://master-api.flutter.dev/flutter/[link_to_relevant_page].html + +[Issue xxxx]: {{site.github}}/flutter/flutter/issues/[link_to_actual_issue] +[Issue yyyy]: {{site.github}}/flutter/flutter/issues/[link_to_actual_issue] +[PR title #1]: {{site.github}}/flutter/flutter/pull/[link_to_actual_pr] +[PR title #2]: {{site.github}}/flutter/flutter/pull/[link_to_actual_pr] +{% endcomment %} diff --git a/src/content/release/breaking-changes/index.md b/src/content/release/breaking-changes/index.md index dd1247b5604..e4b4377fd25 100644 --- a/src/content/release/breaking-changes/index.md +++ b/src/content/release/breaking-changes/index.md @@ -50,6 +50,7 @@ They're sorted by release and listed in alphabetical order: * [Component theme normalization updates][] * [Deprecate `DropdownButtonFormField` `value` parameter in favor of `initialValue`][] * [The Form widget no longer supports being a sliver.][] +* [The default page transition on Android is now PredictiveBackPageTransitionBuilder][] [Redesigned the Radio Widget]: /release/breaking-changes/radio-api-redesign [Removed semantics elevation and thickness]: /release/breaking-changes/remove-semantics-elevation-and-thickness @@ -59,6 +60,7 @@ They're sorted by release and listed in alphabetical order: [Component theme normalization updates]: /release/breaking-changes/component-theme-normalization-updates [Deprecate `DropdownButtonFormField` `value` parameter in favor of `initialValue`]: /release/breaking-changes/deprecate-dropdownbuttonformfield-value [The Form widget no longer supports being a sliver.]:/release/breaking-changes/form-semantics +[The default page transition on Android is now PredictiveBackPageTransitionBuilder]:/release/breaking-changes/default-android-page-transition ### Released in Flutter 3.32 From 09878df54438642ff86de166f501a99117d65855 Mon Sep 17 00:00:00 2001 From: Justin McCandless Date: Mon, 4 Aug 2025 10:21:17 -0700 Subject: [PATCH 2/3] Old title and description changes --- .../breaking-changes/default-android-page-transition.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/content/release/breaking-changes/default-android-page-transition.md b/src/content/release/breaking-changes/default-android-page-transition.md index e1b13890d46..9c5586b0100 100644 --- a/src/content/release/breaking-changes/default-android-page-transition.md +++ b/src/content/release/breaking-changes/default-android-page-transition.md @@ -1,6 +1,7 @@ --- -title: Replace with title of breaking change -description: Brief description similar to the "context" section below. The description shouldn't have any linebreaks - let it go long and wrap. Text below should break at 80 chars or less. +title: The default page transition on Android is now PredictiveBackPageTransitionBuilder +description: Android's default page transition has been updated to match the +platform and to support predictive back. --- {% comment %} From 05ba91768405020c99ef9f724399925d1a33c7b5 Mon Sep 17 00:00:00 2001 From: Justin McCandless Date: Fri, 15 Aug 2025 16:04:02 -0700 Subject: [PATCH 3/3] Everything but description and timeline --- .../default-android-page-transition.md | 201 ++++++++++++++---- 1 file changed, 159 insertions(+), 42 deletions(-) diff --git a/src/content/release/breaking-changes/default-android-page-transition.md b/src/content/release/breaking-changes/default-android-page-transition.md index 9c5586b0100..8847b5fc495 100644 --- a/src/content/release/breaking-changes/default-android-page-transition.md +++ b/src/content/release/breaking-changes/default-android-page-transition.md @@ -1,5 +1,5 @@ --- -title: The default page transition on Android is now PredictiveBackPageTransitionBuilder +title: The default page transition on Android is now PredictiveBackPageTransitionsBuilder description: Android's default page transition has been updated to match the platform and to support predictive back. --- @@ -61,30 +61,29 @@ platform and to support predictive back. ## Summary -{% comment %} - A brief (one- to three-line) summary that gives - context as to what changed so that someone can - find it when browsing through an index of - breaking changes, ideally using keywords from - the symptoms you would see if you had not yet - migrated (for example, the text from probable - error messages). -{% endcomment %} +The default page transition on Android has been updated from +[`ZoomPageTransitionsBuilder`][] to [`PredictiveBackPageTransitionsBuilder`][]. When +not using predictive back, this falls back to +[`FadeForwardsPageTransitionsBuilder`][]. ## Context -{% comment %} - High-level description of what API changed and why. - Should be clear enough to be understandable to someone - who has no context about this breaking change, - such as someone who doesn't know the underlying API. - This section should also answer the question - "what is the problem that led to considering making - a breaking change?" -{% endcomment %} +Android has been rolling out a feature called predictive back, where performing +a back gesture allows the user to peek at the previous route or app and possibly +cancel the navigation. Flutter added support for this with the [`PopScope`][] +widget followed by [`PredictiveBackPageTransitionsBuilder`][]. + +In the meantime, Android also updated its default page transition. Flutter added +support for this with [`FadeForwardsPageTransitionsBuilder`][]. + +Finally with this change, [`PredictiveBackPageTransitionsBuilder`][] has +replaced [`ZoomPageTransitionsBuilder`][] as the default page transition on +Android. Any time that navigation happens without a predictive back gesture, +[`FadeForwardsPageTransitionsBuilder`][] is used. ## Description of change +TODO(justinmc): Maybe take some from Context section above. {% comment %} A technical description of the actual change, with code samples showing how the API changed. @@ -97,32 +96,147 @@ error messages. ## Migration guide -{% comment %} - A description of how to make the change. - If a migration tool is available, - discuss it here. Even if there is a tool, - a description of how to make the change manually - must be provided. This section needs before and - after code examples that are relevant to the - developer. -{% endcomment %} +If you want to keep your app's page transition exactly the same as before, you +can simply set your page transition explicitly in your app's theme. Keep in mind +that you will not be able to support predictive back route transitions. Code before migration: ```dart -// Example of code before the change. +return MaterialApp( + // ThemeData.pageTransitionsTheme is the default. + home: const MyFirstScreen(), +); ``` Code after migration: ```dart -// Example of code after the change. +return MaterialApp( + theme: ThemeData( + // ThemeData.pageTransitionsTheme is explicitly set to the old transition. + pageTransitionsTheme: const PageTransitionsTheme( + builders: { + TargetPlatform.android: ZoomPageTransitionsBuilder(), + }, + ), + ), + home: const MyFirstScreen(), +); +``` + +One side effect of changing the default transition is that the duration that it +takes to transition between pages has increased from 300ms to 450ms. This may +cause breakages in tests that depend on the previous transition duration. +Fortunately, it's possible to use [`TransitionDurationObserver`][] to keep tests +independent of whatever page transition is used. + +Code before migration: + + +```dart +testWidgets('example', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + onGenerateRoute: (RouteSettings settings) { ... }, + ), + ); + + expect(find.text('Page 1'), findsOneWidget); + expect(find.text('Page 2'), findsNothing); + + // Pump through the whole transition, hardcoded to 300ms. + await tester.tap(find.text('Next')); + await tester.pump(const Duration(milliseconds: 300)); + + expect(find.text('Page 1'), findsNothing); + expect(find.text('Page 2'), findsOneWidget); +}); +``` + +Code after migration: + + +```dart +testWidgets('example', (WidgetTester tester) async { + final TransitionDurationObserver observer = TransitionDurationObserver(); + + await tester.pumpWidget( + MaterialApp( + navigatorObservers: [observer], + onGenerateRoute: (RouteSettings settings) { ... }, + ), + ); + + expect(find.text('Page 1'), findsOneWidget); + expect(find.text('Page 2'), findsNothing); + + // Pump through the whole transition independent of the duration. + await tester.tap(find.text('Next')); + await observer.pumpPastTransition(tester); + + expect(find.text('Page 1'), findsNothing); + expect(find.text('Page 2'), findsOneWidget); +}); +``` + +It's even possible to write tests that need to pump part of the way through a +page transition without depending on the exact duration. + +Code before migration: + + +```dart +testWidgets('example', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + onGenerateRoute: (RouteSettings settings) { ... }, + ), + ); + + expect(find.text('Page 1'), findsOneWidget); + expect(find.text('Page 2'), findsNothing); + + // Pump through half of the transition with a hardcoded value. + await tester.tap(find.text('Back')); + await tester.pump(const Duration(milliseconds: 150)); + + expect(find.text('Page 1'), findsOneWidget); + expect(find.text('Page 2'), findsOneWidget); +}); +``` + +Code after migration: + + +```dart +testWidgets('example', (WidgetTester tester) async { + final TransitionDurationObserver observer = TransitionDurationObserver(); + + await tester.pumpWidget( + MaterialApp( + navigatorObservers: [observer], + onGenerateRoute: (RouteSettings settings) { ... }, + ), + ); + + expect(find.text('Page 1'), findsOneWidget); + expect(find.text('Page 2'), findsNothing); + + // Pump through half of the transition independent of the duration. + await tester.tap(find.text('Back')); + await tester.pump(observer.transitionDuration ~/ 2); + + expect(find.text('Page 1'), findsOneWidget); + expect(find.text('Page 2'), findsOneWidget); +}); ``` ## Timeline +TODO(justinmc): Should land any minute now... {% comment %} The version # of the SDK where this change was introduced. If there is a deprecation window, @@ -143,6 +257,7 @@ Reverted in version: xxx (OPTIONAL, delete if not used) ## References +TODO(justinmc) {% comment %} These links are commented out because they cause the GitHubActions (GHA) linkcheck to fail. @@ -154,17 +269,19 @@ Reverted in version: xxx (OPTIONAL, delete if not used) API documentation: -* [`ClassName`][] +* [`ZoomPageTransitionsBuilder`][] +* [`PredictiveBackPageTransitionsBuilder`][] +* [`FadeForwardsPageTransitionsBuilder`][] +* [`PopScope`][] +* [`TransitionDurationObserver`][] Relevant issues: -* [Issue xxxx][] -* [Issue yyyy][] +* [Android predictive back route transitions][] Relevant PRs: -* [PR title #1][] -* [PR title #2][] +* [Predictive back route transitions by default][] {% endcomment %} {% comment %} @@ -183,15 +300,15 @@ Relevant PRs: and a master channel (master-api) link. -[`ClassName`]: {{site.api}}/flutter/[link_to_relevant_page].html +[`ZoomPageTransitionsBuilder`]: {{site.api}}/flutter/material/ZoomPageTransitionsBuilder-class.html +[`PredictiveBackPageTransitionsBuilder`]: {{site.api}}/flutter/material/PredictiveBackPageTransitionsBuilder-class.html +[`FadeForwardsPageTransitionsBuilder`]: {{site.api}}/flutter/material/FadeForwardsPageTransitionsBuilder-class.html +[`PopScope`]: {{site.api}}/flutter/widgets/PopScope-class.html +[`TransitionDurationObserver`]: {{site.api}}/flutter/flutter_test/TransitionDurationObserver-class.html {% include master-api.md %} -[`ClassName`]: https://master-api.flutter.dev/flutter/[link_to_relevant_page].html - -[Issue xxxx]: {{site.github}}/flutter/flutter/issues/[link_to_actual_issue] -[Issue yyyy]: {{site.github}}/flutter/flutter/issues/[link_to_actual_issue] -[PR title #1]: {{site.github}}/flutter/flutter/pull/[link_to_actual_pr] -[PR title #2]: {{site.github}}/flutter/flutter/pull/[link_to_actual_pr] +[Android predictive back route transitions]: {{site.github.com}}/flutter/flutter/issues/131961 +[Predictive back route transitions by default]: {{site.github}}/flutter/flutter/pull/165832 {% endcomment %}