diff --git a/packages/flutter/lib/src/material/page.dart b/packages/flutter/lib/src/material/page.dart index 4ab01b2d59..73d677ff4c 100644 --- a/packages/flutter/lib/src/material/page.dart +++ b/packages/flutter/lib/src/material/page.dart @@ -80,8 +80,6 @@ class MaterialPageRoute extends PageRoute with MaterialRouteTransitionMixi /// * [CupertinoPageTransitionsBuilder], which is the default page transition /// for iOS and macOS. mixin MaterialRouteTransitionMixin on PageRoute { - TargetPlatform? _effectiveTargetPlatform; - /// Builds the primary contents of the route. @protected Widget buildContent(BuildContext context); @@ -118,20 +116,8 @@ mixin MaterialRouteTransitionMixin on PageRoute { @override Widget buildTransitions(BuildContext context, Animation animation, Animation secondaryAnimation, Widget child) { - return ValueListenableBuilder( - valueListenable: navigator!.userGestureInProgressNotifier, - builder: (BuildContext context, bool useGestureInProgress, Widget? _) { - final ThemeData themeData = Theme.of(context); - - if (useGestureInProgress) { - // The platform should be kept unchanged during an user gesture. - _effectiveTargetPlatform ??= themeData.platform; - } else { - _effectiveTargetPlatform = themeData.platform; - } - return themeData.pageTransitionsTheme.buildTransitions(this, context, animation, secondaryAnimation, child, _effectiveTargetPlatform!); - }, - ); + final PageTransitionsTheme theme = Theme.of(context).pageTransitionsTheme; + return theme.buildTransitions(this, context, animation, secondaryAnimation, child); } } diff --git a/packages/flutter/lib/src/material/page_transitions_theme.dart b/packages/flutter/lib/src/material/page_transitions_theme.dart index 6cf76570df..7c960a8362 100644 --- a/packages/flutter/lib/src/material/page_transitions_theme.dart +++ b/packages/flutter/lib/src/material/page_transitions_theme.dart @@ -741,7 +741,7 @@ class PageTransitionsTheme with Diagnosticable { Map get builders => _builders; final Map _builders; - /// Delegates to the builder for the current [platform]. + /// Delegates to the builder for the current [ThemeData.platform]. /// If a builder for the current platform is not found, then the /// [ZoomPageTransitionsBuilder] is used. /// @@ -752,8 +752,13 @@ class PageTransitionsTheme with Diagnosticable { Animation animation, Animation secondaryAnimation, Widget child, - TargetPlatform platform, ) { + TargetPlatform platform = Theme.of(context).platform; + + if (CupertinoRouteTransitionMixin.isPopGestureInProgress(route)) { + platform = TargetPlatform.iOS; + } + final PageTransitionsBuilder matchingBuilder = builders[platform] ?? const ZoomPageTransitionsBuilder(); return matchingBuilder.buildTransitions(route, context, animation, secondaryAnimation, child); diff --git a/packages/flutter/test/material/page_transitions_theme_test.dart b/packages/flutter/test/material/page_transitions_theme_test.dart index e1f933da48..323d4ed0c0 100644 --- a/packages/flutter/test/material/page_transitions_theme_test.dart +++ b/packages/flutter/test/material/page_transitions_theme_test.dart @@ -350,140 +350,4 @@ void main() { await tester.pumpAndSettle(); expect(builtCount, 1); }, variant: TargetPlatformVariant.only(TargetPlatform.android)); - - testWidgets('android can use CupertinoPageTransitionsBuilder', (WidgetTester tester) async { - int builtCount = 0; - - final Map routes = { - '/': (BuildContext context) => Material( - child: TextButton( - child: const Text('push'), - onPressed: () { Navigator.of(context).pushNamed('/b'); }, - ), - ), - '/b': (BuildContext context) => StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - builtCount++; - return TextButton( - child: const Text('pop'), - onPressed: () { Navigator.pop(context); }, - ); - }, - ), - }; - - await tester.pumpWidget( - MaterialApp( - theme: ThemeData( - pageTransitionsTheme: const PageTransitionsTheme( - builders: { - TargetPlatform.android: CupertinoPageTransitionsBuilder(), - // iOS uses different PageTransitionsBuilder - TargetPlatform.iOS: FadeUpwardsPageTransitionsBuilder(), - }, - ), - ), - routes: routes, - ), - ); - - // No matter push or pop was called, the child widget should built only once. - await tester.tap(find.text('push')); - await tester.pumpAndSettle(); - expect(builtCount, 1); - - final Size size = tester.getSize(find.byType(MaterialApp)); - await tester.flingFrom(Offset(0, size.height / 2), Offset(size.width * 2 / 3, 0), 500); - - await tester.pumpAndSettle(); - expect(find.text('push'), findsOneWidget); - expect(builtCount, 1); - }, variant: TargetPlatformVariant.only(TargetPlatform.android)); - - testWidgets('back gesture while TargetPlatform changes', (WidgetTester tester) async { - final Map routes = { - '/': (BuildContext context) => Material( - child: TextButton( - child: const Text('PUSH'), - onPressed: () { Navigator.of(context).pushNamed('/b'); }, - ), - ), - '/b': (BuildContext context) => const Text('HELLO'), - }; - const PageTransitionsTheme pageTransitionsTheme = PageTransitionsTheme( - builders: { - TargetPlatform.android: CupertinoPageTransitionsBuilder(), - // iOS uses different PageTransitionsBuilder - TargetPlatform.iOS: FadeUpwardsPageTransitionsBuilder(), - }, - ); - await tester.pumpWidget( - MaterialApp( - theme: ThemeData( - platform: TargetPlatform.android, - pageTransitionsTheme: pageTransitionsTheme, - ), - routes: routes, - ), - ); - await tester.tap(find.text('PUSH')); - expect(await tester.pumpAndSettle(const Duration(minutes: 1)), 2); - expect(find.text('PUSH'), findsNothing); - expect(find.text('HELLO'), findsOneWidget); - - final Offset helloPosition1 = tester.getCenter(find.text('HELLO')); - final TestGesture gesture = await tester.startGesture(const Offset(2.5, 300.0)); - await tester.pump(const Duration(milliseconds: 20)); - await gesture.moveBy(const Offset(100.0, 0.0)); - expect(find.text('PUSH'), findsNothing); - expect(find.text('HELLO'), findsOneWidget); - await tester.pump(const Duration(milliseconds: 20)); - expect(find.text('PUSH'), findsOneWidget); - expect(find.text('HELLO'), findsOneWidget); - final Offset helloPosition2 = tester.getCenter(find.text('HELLO')); - expect(helloPosition1.dx, lessThan(helloPosition2.dx)); - expect(helloPosition1.dy, helloPosition2.dy); - expect(Theme.of(tester.element(find.text('HELLO'))).platform, TargetPlatform.android); - - await tester.pumpWidget( - MaterialApp( - theme: ThemeData( - platform: TargetPlatform.iOS, - pageTransitionsTheme: pageTransitionsTheme, - ), - routes: routes, - ), - ); - // Now, let the theme animation run through. - // This takes three frames (including the first one above): - // 1. Start the Theme animation. It's at t=0 so everything else is identical. - // 2. Start any animations that are informed by the Theme, for example, the - // DefaultTextStyle, on the first frame that the theme is not at t=0. In - // this case, it's at t=1.0 of the theme animation, so this is also the - // frame in which the theme animation ends. - // 3. End all the other animations. - expect(await tester.pumpAndSettle(const Duration(minutes: 1)), 2); - expect(Theme.of(tester.element(find.text('HELLO'))).platform, TargetPlatform.iOS); - final Offset helloPosition3 = tester.getCenter(find.text('HELLO')); - expect(helloPosition3, helloPosition2); - expect(find.text('PUSH'), findsOneWidget); - expect(find.text('HELLO'), findsOneWidget); - await gesture.moveBy(const Offset(100.0, 0.0)); - await tester.pump(const Duration(milliseconds: 20)); - expect(find.text('PUSH'), findsOneWidget); - expect(find.text('HELLO'), findsOneWidget); - final Offset helloPosition4 = tester.getCenter(find.text('HELLO')); - expect(helloPosition3.dx, lessThan(helloPosition4.dx)); - expect(helloPosition3.dy, helloPosition4.dy); - await gesture.moveBy(const Offset(500.0, 0.0)); - await gesture.up(); - expect(await tester.pumpAndSettle(const Duration(minutes: 1)), 3); - expect(find.text('PUSH'), findsOneWidget); - expect(find.text('HELLO'), findsNothing); - - await tester.tap(find.text('PUSH')); - expect(await tester.pumpAndSettle(const Duration(minutes: 1)), 2); - expect(find.text('PUSH'), findsNothing); - expect(find.text('HELLO'), findsOneWidget); - }); }