La transición de página predeterminada en Android ahora es PredictiveBackPageTransitionsBuilder
La transición de página predeterminada de Android se ha actualizado para coincidir con la plataforma y para soportar el retroceso predictivo (predictive back).
Resumen
#La transición de página predeterminada en Android se ha actualizado de
ZoomPageTransitionsBuilder
a PredictiveBackPageTransitionsBuilder.
Cuando no se utiliza el retroceso predictivo, esta recurre a
FadeForwardsPageTransitionsBuilder.
Contexto
#Android ha estado implementando una función llamada retroceso predictivo (predictive back), en la cual realizar
un gesto de retroceso permite al usuario echar un vistazo a la ruta o aplicación anterior y, posiblemente,
cancelar la navegación. Flutter añadió soporte para esto con el
widget PopScope seguido de PredictiveBackPageTransitionsBuilder.
Mientras tanto, Android también actualizó su transición de página predeterminada. Flutter añadió
soporte para esto con FadeForwardsPageTransitionsBuilder.
Descripción del cambio
#Con este cambio, PredictiveBackPageTransitionsBuilder
ha reemplazado a
ZoomPageTransitionsBuilder
como la transición de página predeterminada en Android.
Durante una transición de página normal sin un gesto de retroceso predictivo, los usuarios
verán la nueva FadeForwardsPageTransitionsBuilder
como la transición de página
predeterminada. Al usar un gesto de retroceso predictivo, la página se anima junto
con el gesto y permite cancelar o confirmar la navegación hacia atrás.
En este ejemplo, no se proporciona explícitamente ninguna transición de página, por lo que el
default
se establece en PredictiveBackPageTransitionsBuilder
en el tema de Android.
MaterialApp(
theme: ThemeData(
brightness: Brightness.light,
),
home: const PageOne(),
);
Guía de migración
#Si deseas mantener la transición de página de tu aplicación en la antigua
ZoomPageTransitionsBuilder, simplemente puedes establecer tu transición de página
explícitamente en el tema de tu aplicación. Ten en cuenta que no podrás
soportar las transiciones de ruta de retroceso predictivo.
Código antes de la migración:
return MaterialApp(
theme: ThemeData(
brightness: Brightness.light,
// pageTransitionsTheme is the default.
),
home: const MyFirstScreen(),
);
Código después de la migración:
MaterialApp(
theme: ThemeData(
// pageTransitionsTheme is explicitly set to the old transition on Android.
pageTransitionsTheme: const PageTransitionsTheme(
builders: {
TargetPlatform.android: ZoomPageTransitionsBuilder(),
},
),
),
home: const MyFirstScreen(),
);
Un efecto secundario de cambiar la transición predeterminada es que la duración que toma
la transición entre páginas ha aumentado de 300ms a 450ms. Esto podría
causar fallos en las pruebas que dependen de la duración de transición anterior.
Afortunadamente, es posible usar TransitionDurationObserver
para mantener las pruebas
independientes de cualquier transición de página que se utilice.
Código antes de la migración:
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);
});
Código después de la migración:
testWidgets('example', (WidgetTester tester) async {
final TransitionDurationObserver observer = TransitionDurationObserver();
await tester.pumpWidget(
MaterialApp(
navigatorObservers: <NavigatorObserver>[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);
});
Incluso es posible escribir pruebas que necesitan procesar parte del camino a través de una transición de página sin depender de la duración exacta.
Código antes de la migración:
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);
});
Código después de la migración:
testWidgets('example', (WidgetTester tester) async {
final TransitionDurationObserver observer = TransitionDurationObserver();
await tester.pumpWidget(
MaterialApp(
navigatorObservers: <NavigatorObserver>[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
#Introducido en la versión: 3.37.0-0.0.pre
En la versión estable: 3.38.0
Referencias
#Documentación de la API:
-
ZoomPageTransitionsBuilder -
PredictiveBackPageTransitionsBuilder -
FadeForwardsPageTransitionsBuilder PopScope-
TransitionDurationObserver
Issues relevantes:
PRs relevantes:
A menos que se indique lo contrario, la documentación de este sitio refleja Flutter 3.44.0. Página actualizada por última vez el 2026-05-05. Ver código fuente oreportar un problema.