@@ -7,6 +7,7 @@ import 'dart:ui' as ui;
77import 'package:flutter/cupertino.dart' ;
88import 'package:flutter/foundation.dart' ;
99import 'package:flutter/rendering.dart' ;
10+ import 'package:flutter/services.dart' ;
1011
1112import 'colors.dart' ;
1213import 'theme.dart' ;
@@ -545,6 +546,9 @@ abstract class PageTransitionsBuilder {
545546/// that's similar to the one provided in Android Q.
546547/// * [CupertinoPageTransitionsBuilder] , which defines a horizontal page
547548/// transition that matches native iOS page transitions.
549+ /// * [PredictiveBackPageTransitionsBuilder] , which defines a page
550+ /// transition that allows peeking behind the current route on Android U and
551+ /// above.
548552class FadeUpwardsPageTransitionsBuilder extends PageTransitionsBuilder {
549553 /// Constructs a page transition animation that slides the page up.
550554 const FadeUpwardsPageTransitionsBuilder ();
@@ -573,6 +577,8 @@ class FadeUpwardsPageTransitionsBuilder extends PageTransitionsBuilder {
573577/// that's similar to the one provided in Android Q.
574578/// * [CupertinoPageTransitionsBuilder] , which defines a horizontal page
575579/// transition that matches native iOS page transitions.
580+ /// * [PredictiveBackPageTransitionsBuilder] , which defines a page
581+ /// transition that allows peeking behind the current route on Android.
576582class OpenUpwardsPageTransitionsBuilder extends PageTransitionsBuilder {
577583 /// Constructs a page transition animation that matches the transition used on
578584 /// Android P.
@@ -606,6 +612,8 @@ class OpenUpwardsPageTransitionsBuilder extends PageTransitionsBuilder {
606612/// that's similar to the one provided by Android P.
607613/// * [CupertinoPageTransitionsBuilder] , which defines a horizontal page
608614/// transition that matches native iOS page transitions.
615+ /// * [PredictiveBackPageTransitionsBuilder] , which defines a page
616+ /// transition that allows peeking behind the current route on Android.
609617class ZoomPageTransitionsBuilder extends PageTransitionsBuilder {
610618 /// Constructs a page transition animation that matches the transition used on
611619 /// Android Q.
@@ -656,11 +664,11 @@ class ZoomPageTransitionsBuilder extends PageTransitionsBuilder {
656664
657665 @override
658666 Widget buildTransitions <T >(
659- PageRoute <T >? route,
660- BuildContext ? context,
667+ PageRoute <T > route,
668+ BuildContext context,
661669 Animation <double > animation,
662670 Animation <double > secondaryAnimation,
663- Widget ? child,
671+ Widget child,
664672 ) {
665673 if (_kProfileForceDisableSnapshotting) {
666674 return _ZoomPageTransitionNoCache (
@@ -672,7 +680,7 @@ class ZoomPageTransitionsBuilder extends PageTransitionsBuilder {
672680 return _ZoomPageTransition (
673681 animation: animation,
674682 secondaryAnimation: secondaryAnimation,
675- allowSnapshotting: allowSnapshotting && ( route? .allowSnapshotting ?? true ) ,
683+ allowSnapshotting: allowSnapshotting && route.allowSnapshotting,
676684 allowEnterRouteSnapshotting: allowEnterRouteSnapshotting,
677685 child: child,
678686 );
@@ -690,6 +698,8 @@ class ZoomPageTransitionsBuilder extends PageTransitionsBuilder {
690698/// that's similar to the one provided by Android P.
691699/// * [ZoomPageTransitionsBuilder] , which defines the default page transition
692700/// that's similar to the one provided in Android Q.
701+ /// * [PredictiveBackPageTransitionsBuilder] , which defines a page
702+ /// transition that allows peeking behind the current route on Android.
693703class CupertinoPageTransitionsBuilder extends PageTransitionsBuilder {
694704 /// Constructs a page transition animation that matches the iOS transition.
695705 const CupertinoPageTransitionsBuilder ();
@@ -741,7 +751,9 @@ class PageTransitionsTheme with Diagnosticable {
741751 /// By default the list of builders is: [ZoomPageTransitionsBuilder]
742752 /// for [TargetPlatform.android] , and [CupertinoPageTransitionsBuilder] for
743753 /// [TargetPlatform.iOS] and [TargetPlatform.macOS] .
744- const PageTransitionsTheme ({ Map <TargetPlatform , PageTransitionsBuilder > builders = _defaultBuilders }) : _builders = builders;
754+ const PageTransitionsTheme ({
755+ Map <TargetPlatform , PageTransitionsBuilder > builders = _defaultBuilders,
756+ }) : _builders = builders;
745757
746758 static const Map <TargetPlatform , PageTransitionsBuilder > _defaultBuilders = < TargetPlatform , PageTransitionsBuilder > {
747759 TargetPlatform .android: ZoomPageTransitionsBuilder (),
@@ -765,17 +777,13 @@ class PageTransitionsTheme with Diagnosticable {
765777 Animation <double > secondaryAnimation,
766778 Widget child,
767779 ) {
768- TargetPlatform platform = Theme .of (context).platform;
769-
770- if (CupertinoRouteTransitionMixin .isPopGestureInProgress (route)) {
771- platform = TargetPlatform .iOS;
772- }
773-
774- final PageTransitionsBuilder matchingBuilder = builders[platform] ?? switch (platform) {
775- TargetPlatform .iOS => const CupertinoPageTransitionsBuilder (),
776- TargetPlatform .android || TargetPlatform .fuchsia || TargetPlatform .windows || TargetPlatform .macOS || TargetPlatform .linux => const ZoomPageTransitionsBuilder (),
777- };
778- return matchingBuilder.buildTransitions <T >(route, context, animation, secondaryAnimation, child);
780+ return _PageTransitionsThemeTransitions <T >(
781+ builders: builders,
782+ route: route,
783+ animation: animation,
784+ secondaryAnimation: secondaryAnimation,
785+ child: child,
786+ );
779787 }
780788
781789 // Map the builders to a list with one PageTransitionsBuilder per platform for
@@ -815,6 +823,55 @@ class PageTransitionsTheme with Diagnosticable {
815823 }
816824}
817825
826+ class _PageTransitionsThemeTransitions <T > extends StatefulWidget {
827+ const _PageTransitionsThemeTransitions ({
828+ required this .builders,
829+ required this .route,
830+ required this .animation,
831+ required this .secondaryAnimation,
832+ required this .child,
833+ });
834+
835+ final Map <TargetPlatform , PageTransitionsBuilder > builders;
836+ final PageRoute <T > route;
837+ final Animation <double > animation;
838+ final Animation <double > secondaryAnimation;
839+ final Widget child;
840+
841+ @override
842+ State <_PageTransitionsThemeTransitions <T >> createState () => _PageTransitionsThemeTransitionsState <T >();
843+ }
844+
845+ class _PageTransitionsThemeTransitionsState <T > extends State <_PageTransitionsThemeTransitions <T >> {
846+ TargetPlatform ? _transitionPlatform;
847+
848+ @override
849+ Widget build (BuildContext context) {
850+ TargetPlatform platform = Theme .of (context).platform;
851+
852+ // If the theme platform is changed in the middle of a pop gesture, keep the
853+ // transition that the gesture began with until the gesture is finished.
854+ if (widget.route.popGestureInProgress) {
855+ _transitionPlatform ?? = platform;
856+ platform = _transitionPlatform! ;
857+ } else {
858+ _transitionPlatform = null ;
859+ }
860+
861+ final PageTransitionsBuilder matchingBuilder = widget.builders[platform] ?? switch (platform) {
862+ TargetPlatform .iOS => const CupertinoPageTransitionsBuilder (),
863+ TargetPlatform .android || TargetPlatform .fuchsia || TargetPlatform .windows || TargetPlatform .macOS || TargetPlatform .linux => const ZoomPageTransitionsBuilder (),
864+ };
865+ return matchingBuilder.buildTransitions <T >(
866+ widget.route,
867+ context,
868+ widget.animation,
869+ widget.secondaryAnimation,
870+ widget.child,
871+ );
872+ }
873+ }
874+
818875// Take an image and draw it centered and scaled. The image is already scaled by the [pixelRatio].
819876void _drawImageScaledAndCentered (PaintingContext context, ui.Image image, double scale, double opacity, double pixelRatio) {
820877 if (scale <= 0.0 || opacity <= 0.0 ) {
0 commit comments