Android Q transition by default (#82670)
This commit is contained in:
parent
463f9739f7
commit
a1ae4feac5
@ -63,13 +63,14 @@ class MaterialPageRoute<T> extends PageRoute<T> with MaterialRouteTransitionMixi
|
|||||||
/// A mixin that provides platform-adaptive transitions for a [PageRoute].
|
/// A mixin that provides platform-adaptive transitions for a [PageRoute].
|
||||||
///
|
///
|
||||||
/// {@template flutter.material.materialRouteTransitionMixin}
|
/// {@template flutter.material.materialRouteTransitionMixin}
|
||||||
/// For Android, the entrance transition for the page slides the route upwards
|
/// For Android, the entrance transition for the page zooms in while the
|
||||||
/// and fades it in. The exit transition is the same, but in reverse.
|
/// exiting page zooms and fades out. The exit transition is similar, but in
|
||||||
|
/// reverse.
|
||||||
///
|
///
|
||||||
/// The transition is adaptive to the platform and on iOS, the route slides in
|
/// For iOS, the page slides in from the right and exits in reverse. The page
|
||||||
/// from the right and exits in reverse. The route also shifts to the left in
|
/// also shifts to the left in parallax when another page enters to cover it.
|
||||||
/// parallax when another page enters to cover it. (These directions are flipped
|
/// (These directions are flipped in environments with a right-to-left reading
|
||||||
/// in environments with a right-to-left reading direction.)
|
/// direction.)
|
||||||
/// {@endtemplate}
|
/// {@endtemplate}
|
||||||
///
|
///
|
||||||
/// See also:
|
/// See also:
|
||||||
|
@ -9,7 +9,8 @@ import 'colors.dart';
|
|||||||
import 'theme.dart';
|
import 'theme.dart';
|
||||||
|
|
||||||
// Slides the page upwards and fades it in, starting from 1/4 screen
|
// Slides the page upwards and fades it in, starting from 1/4 screen
|
||||||
// below the top.
|
// below the top. The transition is intended to match the default for
|
||||||
|
// Android O.
|
||||||
class _FadeUpwardsPageTransition extends StatelessWidget {
|
class _FadeUpwardsPageTransition extends StatelessWidget {
|
||||||
_FadeUpwardsPageTransition({
|
_FadeUpwardsPageTransition({
|
||||||
Key? key,
|
Key? key,
|
||||||
@ -146,7 +147,7 @@ class _OpenUpwardsPageTransition extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Zooms and fades a new page in, zooming out the previous page. This transition
|
// Zooms and fades a new page in, zooming out the previous page. This transition
|
||||||
// is designed to match the Android 10 activity transition.
|
// is designed to match the Android Q activity transition.
|
||||||
class _ZoomPageTransition extends StatelessWidget {
|
class _ZoomPageTransition extends StatelessWidget {
|
||||||
/// Creates a [_ZoomPageTransition].
|
/// Creates a [_ZoomPageTransition].
|
||||||
///
|
///
|
||||||
@ -291,16 +292,16 @@ class _ZoomEnterTransition extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
double opacity = 0;
|
double opacity = 0;
|
||||||
// The transition's scrim opacity only increases on the forward transition. In the reverse
|
// The transition's scrim opacity only increases on the forward transition.
|
||||||
// transition, the opacity should always be 0.0.
|
// In the reverse transition, the opacity should always be 0.0.
|
||||||
//
|
//
|
||||||
// Therefore, we need to only apply the scrim opacity animation when the transition
|
// Therefore, we need to only apply the scrim opacity animation when
|
||||||
// is running forwards.
|
// the transition is running forwards.
|
||||||
//
|
//
|
||||||
// The reason that we check that the animation's status is not `completed` instead
|
// The reason that we check that the animation's status is not `completed`
|
||||||
// of checking that it is `forward` is that this allows the interrupted reversal of the
|
// instead of checking that it is `forward` is that this allows
|
||||||
// forward transition to smoothly fade the scrim away. This prevents a disjointed
|
// the interrupted reversal of the forward transition to smoothly fade
|
||||||
// removal of the scrim.
|
// the scrim away. This prevents a disjointed removal of the scrim.
|
||||||
if (!reverse && animation.status != AnimationStatus.completed) {
|
if (!reverse && animation.status != AnimationStatus.completed) {
|
||||||
opacity = _scrimOpacityTween.evaluate(animation)!;
|
opacity = _scrimOpacityTween.evaluate(animation)!;
|
||||||
}
|
}
|
||||||
@ -317,17 +318,14 @@ class _ZoomEnterTransition extends StatelessWidget {
|
|||||||
return AnimatedBuilder(
|
return AnimatedBuilder(
|
||||||
animation: animation,
|
animation: animation,
|
||||||
builder: (BuildContext context, Widget? child) {
|
builder: (BuildContext context, Widget? child) {
|
||||||
return Container(
|
return ColoredBox(
|
||||||
color: Colors.black.withOpacity(opacity),
|
color: Colors.black.withOpacity(opacity),
|
||||||
child: child,
|
child: child,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
child: FadeTransition(
|
child: FadeTransition(
|
||||||
opacity: fadeTransition,
|
opacity: fadeTransition,
|
||||||
child: ScaleTransition(
|
child: ScaleTransition(scale: scaleTransition, child: child),
|
||||||
scale: scaleTransition,
|
|
||||||
child: child,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -374,10 +372,7 @@ class _ZoomExitTransition extends StatelessWidget {
|
|||||||
|
|
||||||
return FadeTransition(
|
return FadeTransition(
|
||||||
opacity: fadeTransition,
|
opacity: fadeTransition,
|
||||||
child: ScaleTransition(
|
child: ScaleTransition(scale: scaleTransition, child: child),
|
||||||
scale: scaleTransition,
|
|
||||||
child: child,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -391,11 +386,12 @@ class _ZoomExitTransition extends StatelessWidget {
|
|||||||
///
|
///
|
||||||
/// See also:
|
/// See also:
|
||||||
///
|
///
|
||||||
/// * [FadeUpwardsPageTransitionsBuilder], which defines a default page transition.
|
/// * [FadeUpwardsPageTransitionsBuilder], which defines a page transition
|
||||||
|
/// that's similar to the one provided by Android O.
|
||||||
/// * [OpenUpwardsPageTransitionsBuilder], which defines a page transition
|
/// * [OpenUpwardsPageTransitionsBuilder], which defines a page transition
|
||||||
/// that's similar to the one provided by Android P.
|
/// that's similar to the one provided by Android P.
|
||||||
/// * [ZoomPageTransitionsBuilder], which defines a page transition similar
|
/// * [ZoomPageTransitionsBuilder], which defines the default page transition
|
||||||
/// to the one provided in Android 10.
|
/// that's similar to the one provided in Android Q.
|
||||||
/// * [CupertinoPageTransitionsBuilder], which defines a horizontal page
|
/// * [CupertinoPageTransitionsBuilder], which defines a horizontal page
|
||||||
/// transition that matches native iOS page transitions.
|
/// transition that matches native iOS page transitions.
|
||||||
abstract class PageTransitionsBuilder {
|
abstract class PageTransitionsBuilder {
|
||||||
@ -419,18 +415,19 @@ abstract class PageTransitionsBuilder {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Used by [PageTransitionsTheme] to define a default [MaterialPageRoute] page
|
/// Used by [PageTransitionsTheme] to define a vertically fading
|
||||||
/// transition animation.
|
/// [MaterialPageRoute] page transition animation that looks like
|
||||||
|
/// the default page transition used on Android O.
|
||||||
///
|
///
|
||||||
/// The default animation fades the new page in while translating it upwards,
|
/// The animation fades the new page in while translating it upwards,
|
||||||
/// starting from about 25% below the top of the screen.
|
/// starting from about 25% below the top of the screen.
|
||||||
///
|
///
|
||||||
/// See also:
|
/// See also:
|
||||||
///
|
///
|
||||||
/// * [OpenUpwardsPageTransitionsBuilder], which defines a page transition
|
/// * [OpenUpwardsPageTransitionsBuilder], which defines a page transition
|
||||||
/// that's similar to the one provided by Android P.
|
/// that's similar to the one provided by Android P.
|
||||||
/// * [ZoomPageTransitionsBuilder], which defines a page transition similar
|
/// * [ZoomPageTransitionsBuilder], which defines the default page transition
|
||||||
/// to the one provided in Android 10.
|
/// that's similar to the one provided in Android Q.
|
||||||
/// * [CupertinoPageTransitionsBuilder], which defines a horizontal page
|
/// * [CupertinoPageTransitionsBuilder], which defines a horizontal page
|
||||||
/// transition that matches native iOS page transitions.
|
/// transition that matches native iOS page transitions.
|
||||||
class FadeUpwardsPageTransitionsBuilder extends PageTransitionsBuilder {
|
class FadeUpwardsPageTransitionsBuilder extends PageTransitionsBuilder {
|
||||||
@ -455,9 +452,10 @@ class FadeUpwardsPageTransitionsBuilder extends PageTransitionsBuilder {
|
|||||||
///
|
///
|
||||||
/// See also:
|
/// See also:
|
||||||
///
|
///
|
||||||
/// * [FadeUpwardsPageTransitionsBuilder], which defines a default page transition.
|
/// * [FadeUpwardsPageTransitionsBuilder], which defines a page transition
|
||||||
/// * [ZoomPageTransitionsBuilder], which defines a page transition similar
|
/// that's similar to the one provided by Android O.
|
||||||
/// to the one provided in Android 10.
|
/// * [ZoomPageTransitionsBuilder], which defines the default page transition
|
||||||
|
/// that's similar to the one provided in Android Q.
|
||||||
/// * [CupertinoPageTransitionsBuilder], which defines a horizontal page
|
/// * [CupertinoPageTransitionsBuilder], which defines a horizontal page
|
||||||
/// transition that matches native iOS page transitions.
|
/// transition that matches native iOS page transitions.
|
||||||
class OpenUpwardsPageTransitionsBuilder extends PageTransitionsBuilder {
|
class OpenUpwardsPageTransitionsBuilder extends PageTransitionsBuilder {
|
||||||
@ -483,18 +481,19 @@ class OpenUpwardsPageTransitionsBuilder extends PageTransitionsBuilder {
|
|||||||
|
|
||||||
/// Used by [PageTransitionsTheme] to define a zooming [MaterialPageRoute] page
|
/// Used by [PageTransitionsTheme] to define a zooming [MaterialPageRoute] page
|
||||||
/// transition animation that looks like the default page transition used on
|
/// transition animation that looks like the default page transition used on
|
||||||
/// Android 10.
|
/// Android Q.
|
||||||
///
|
///
|
||||||
/// See also:
|
/// See also:
|
||||||
///
|
///
|
||||||
/// * [FadeUpwardsPageTransitionsBuilder], which defines a default page transition.
|
/// * [FadeUpwardsPageTransitionsBuilder], which defines a page transition
|
||||||
|
/// that's similar to the one provided by Android O.
|
||||||
/// * [OpenUpwardsPageTransitionsBuilder], which defines a page transition
|
/// * [OpenUpwardsPageTransitionsBuilder], which defines a page transition
|
||||||
/// similar to the one provided by Android P.
|
/// that's similar to the one provided by Android P.
|
||||||
/// * [CupertinoPageTransitionsBuilder], which defines a horizontal page
|
/// * [CupertinoPageTransitionsBuilder], which defines a horizontal page
|
||||||
/// transition that matches native iOS page transitions.
|
/// transition that matches native iOS page transitions.
|
||||||
class ZoomPageTransitionsBuilder extends PageTransitionsBuilder {
|
class ZoomPageTransitionsBuilder extends PageTransitionsBuilder {
|
||||||
/// Constructs a page transition animation that matches the transition used on
|
/// Constructs a page transition animation that matches the transition used on
|
||||||
/// Android 10.
|
/// Android Q.
|
||||||
const ZoomPageTransitionsBuilder();
|
const ZoomPageTransitionsBuilder();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -518,11 +517,12 @@ class ZoomPageTransitionsBuilder extends PageTransitionsBuilder {
|
|||||||
///
|
///
|
||||||
/// See also:
|
/// See also:
|
||||||
///
|
///
|
||||||
/// * [FadeUpwardsPageTransitionsBuilder], which defines a default page transition.
|
/// * [FadeUpwardsPageTransitionsBuilder], which defines a page transition
|
||||||
|
/// that's similar to the one provided by Android O.
|
||||||
/// * [OpenUpwardsPageTransitionsBuilder], which defines a page transition
|
/// * [OpenUpwardsPageTransitionsBuilder], which defines a page transition
|
||||||
/// that's similar to the one provided by Android P.
|
/// that's similar to the one provided by Android P.
|
||||||
/// * [ZoomPageTransitionsBuilder], which defines a page transition similar
|
/// * [ZoomPageTransitionsBuilder], which defines the default page transition
|
||||||
/// to the one provided in Android 10.
|
/// that's similar to the one provided in Android Q.
|
||||||
class CupertinoPageTransitionsBuilder extends PageTransitionsBuilder {
|
class CupertinoPageTransitionsBuilder extends PageTransitionsBuilder {
|
||||||
/// Constructs a page transition animation that matches the iOS transition.
|
/// Constructs a page transition animation that matches the iOS transition.
|
||||||
const CupertinoPageTransitionsBuilder();
|
const CupertinoPageTransitionsBuilder();
|
||||||
@ -554,9 +554,12 @@ class CupertinoPageTransitionsBuilder extends PageTransitionsBuilder {
|
|||||||
///
|
///
|
||||||
/// * [ThemeData.pageTransitionsTheme], which defines the default page
|
/// * [ThemeData.pageTransitionsTheme], which defines the default page
|
||||||
/// transitions for the overall theme.
|
/// transitions for the overall theme.
|
||||||
/// * [FadeUpwardsPageTransitionsBuilder], which defines a default page transition.
|
/// * [FadeUpwardsPageTransitionsBuilder], which defines a page transition
|
||||||
|
/// that's similar to the one provided by Android O.
|
||||||
/// * [OpenUpwardsPageTransitionsBuilder], which defines a page transition
|
/// * [OpenUpwardsPageTransitionsBuilder], which defines a page transition
|
||||||
/// that's similar to the one provided by Android P.
|
/// that's similar to the one provided by Android P.
|
||||||
|
/// * [ZoomPageTransitionsBuilder], which defines the default page transition
|
||||||
|
/// that's similar to the one provided by Android Q.
|
||||||
/// * [CupertinoPageTransitionsBuilder], which defines a horizontal page
|
/// * [CupertinoPageTransitionsBuilder], which defines a horizontal page
|
||||||
/// transition that matches native iOS page transitions.
|
/// transition that matches native iOS page transitions.
|
||||||
@immutable
|
@immutable
|
||||||
@ -574,9 +577,9 @@ class PageTransitionsTheme with Diagnosticable {
|
|||||||
|
|
||||||
static const Map<TargetPlatform, PageTransitionsBuilder> _defaultBuilders = <TargetPlatform, PageTransitionsBuilder>{
|
static const Map<TargetPlatform, PageTransitionsBuilder> _defaultBuilders = <TargetPlatform, PageTransitionsBuilder>{
|
||||||
// Only have default transitions for mobile platforms
|
// Only have default transitions for mobile platforms
|
||||||
TargetPlatform.android: FadeUpwardsPageTransitionsBuilder(),
|
TargetPlatform.android: ZoomPageTransitionsBuilder(),
|
||||||
TargetPlatform.iOS: CupertinoPageTransitionsBuilder(),
|
TargetPlatform.iOS: CupertinoPageTransitionsBuilder(),
|
||||||
TargetPlatform.fuchsia: FadeUpwardsPageTransitionsBuilder(),
|
TargetPlatform.fuchsia: ZoomPageTransitionsBuilder(),
|
||||||
};
|
};
|
||||||
|
|
||||||
static const Map<TargetPlatform, PageTransitionsBuilder> _defaultWebBuilders = <TargetPlatform, PageTransitionsBuilder>{
|
static const Map<TargetPlatform, PageTransitionsBuilder> _defaultWebBuilders = <TargetPlatform, PageTransitionsBuilder>{
|
||||||
@ -587,8 +590,7 @@ class PageTransitionsTheme with Diagnosticable {
|
|||||||
Map<TargetPlatform, PageTransitionsBuilder> get builders => _builders;
|
Map<TargetPlatform, PageTransitionsBuilder> get builders => _builders;
|
||||||
final Map<TargetPlatform, PageTransitionsBuilder> _builders;
|
final Map<TargetPlatform, PageTransitionsBuilder> _builders;
|
||||||
|
|
||||||
/// Delegates to the builder for the current [ThemeData.platform]
|
/// Delegates to the builder for the current [ThemeData.platform].
|
||||||
/// or [FadeUpwardsPageTransitionsBuilder].
|
|
||||||
///
|
///
|
||||||
/// [MaterialPageRoute.buildTransitions] delegates to this method.
|
/// [MaterialPageRoute.buildTransitions] delegates to this method.
|
||||||
Widget buildTransitions<T>(
|
Widget buildTransitions<T>(
|
||||||
|
@ -459,7 +459,7 @@ void main() {
|
|||||||
home: Material(child: buildTable(sortAscending: true)),
|
home: Material(child: buildTable(sortAscending: true)),
|
||||||
));
|
));
|
||||||
// The `tester.widget` ensures that there is exactly one upward arrow.
|
// The `tester.widget` ensures that there is exactly one upward arrow.
|
||||||
Transform transformOfArrow = tester.widget<Transform>(find.widgetWithIcon(Transform, Icons.arrow_upward));
|
Transform transformOfArrow = tester.firstWidget<Transform>(find.widgetWithIcon(Transform, Icons.arrow_upward));
|
||||||
expect(
|
expect(
|
||||||
transformOfArrow.transform.getRotation(),
|
transformOfArrow.transform.getRotation(),
|
||||||
equals(Matrix3.identity()),
|
equals(Matrix3.identity()),
|
||||||
@ -471,7 +471,7 @@ void main() {
|
|||||||
));
|
));
|
||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
// The `tester.widget` ensures that there is exactly one upward arrow.
|
// The `tester.widget` ensures that there is exactly one upward arrow.
|
||||||
transformOfArrow = tester.widget<Transform>(find.widgetWithIcon(Transform, Icons.arrow_upward));
|
transformOfArrow = tester.firstWidget<Transform>(find.widgetWithIcon(Transform, Icons.arrow_upward));
|
||||||
expect(
|
expect(
|
||||||
transformOfArrow.transform.getRotation(),
|
transformOfArrow.transform.getRotation(),
|
||||||
equals(Matrix3.rotationZ(math.pi)),
|
equals(Matrix3.rotationZ(math.pi)),
|
||||||
|
@ -98,7 +98,12 @@ void main() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
final RenderBox clipRect = tester.renderObject(find.byType(ClipRect).first);
|
final RenderBox clipRect = tester.renderObject(find.byType(ClipRect).first);
|
||||||
final Transform transform = tester.firstWidget(find.byType(Transform));
|
final Transform transform = tester.firstWidget(
|
||||||
|
find.descendant(
|
||||||
|
of: find.byType(FlexibleSpaceBar),
|
||||||
|
matching: find.byType(Transform),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
// The current (200) is half way between the min (100) and max (300) and the
|
// The current (200) is half way between the min (100) and max (300) and the
|
||||||
// lerp values used to calculate the scale are 1 and 1.5, so we check for 1.25.
|
// lerp values used to calculate the scale are 1 and 1.5, so we check for 1.25.
|
||||||
|
@ -12,6 +12,24 @@ import '../rendering/mock_canvas.dart';
|
|||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
testWidgets('test page transition', (WidgetTester tester) async {
|
testWidgets('test page transition', (WidgetTester tester) async {
|
||||||
|
Iterable<T> _findWidgets<T extends Widget>(Finder of) {
|
||||||
|
return tester.widgetList<T>(
|
||||||
|
find.ancestor(of: of, matching: find.byType(T)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
FadeTransition _findForwardFadeTransition(Finder of) {
|
||||||
|
return _findWidgets<FadeTransition>(of).where(
|
||||||
|
(FadeTransition t) => t.opacity.status == AnimationStatus.forward,
|
||||||
|
).first;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScaleTransition _findForwardScaleTransition(Finder of) {
|
||||||
|
return _findWidgets<ScaleTransition>(of).where(
|
||||||
|
(ScaleTransition t) => t.scale.status == AnimationStatus.forward,
|
||||||
|
).first;
|
||||||
|
}
|
||||||
|
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
MaterialApp(
|
MaterialApp(
|
||||||
home: const Material(child: Text('Page 1')),
|
home: const Material(child: Text('Page 1')),
|
||||||
@ -23,47 +41,46 @@ void main() {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
final Offset widget1TopLeft = tester.getTopLeft(find.text('Page 1'));
|
|
||||||
|
|
||||||
tester.state<NavigatorState>(find.byType(Navigator)).pushNamed('/next');
|
tester.state<NavigatorState>(find.byType(Navigator)).pushNamed('/next');
|
||||||
await tester.pump();
|
await tester.pump();
|
||||||
|
await tester.pump(const Duration(milliseconds: 50));
|
||||||
|
|
||||||
|
ScaleTransition widget1Scale = _findForwardScaleTransition(find.text('Page 1'));
|
||||||
|
ScaleTransition widget2Scale = _findForwardScaleTransition(find.text('Page 2'));
|
||||||
|
FadeTransition widget2Opacity = _findForwardFadeTransition(find.text('Page 2'));
|
||||||
|
|
||||||
|
// Page 1 is enlarging, starts from 1.0.
|
||||||
|
expect(widget1Scale.scale.value, greaterThan(1.0));
|
||||||
|
// Page 2 is enlarging from the value less than 1.0.
|
||||||
|
expect(widget2Scale.scale.value, lessThan(1.0));
|
||||||
|
// Page 2 is becoming none transparent.
|
||||||
|
expect(widget2Opacity.opacity.value, lessThan(1.0));
|
||||||
|
|
||||||
|
await tester.pump(const Duration(milliseconds: 250));
|
||||||
await tester.pump(const Duration(milliseconds: 1));
|
await tester.pump(const Duration(milliseconds: 1));
|
||||||
|
|
||||||
FadeTransition widget2Opacity =
|
|
||||||
tester.element(find.text('Page 2')).findAncestorWidgetOfExactType<FadeTransition>()!;
|
|
||||||
Offset widget2TopLeft = tester.getTopLeft(find.text('Page 2'));
|
|
||||||
final Size widget2Size = tester.getSize(find.text('Page 2'));
|
|
||||||
|
|
||||||
// Android transition is vertical only.
|
|
||||||
expect(widget1TopLeft.dx == widget2TopLeft.dx, true);
|
|
||||||
// Page 1 is above page 2 mid-transition.
|
|
||||||
expect(widget1TopLeft.dy < widget2TopLeft.dy, true);
|
|
||||||
// Animation begins 3/4 of the way up the page.
|
|
||||||
expect(widget2TopLeft.dy < widget2Size.height / 4.0, true);
|
|
||||||
// Animation starts with page 2 being near transparent.
|
|
||||||
expect(widget2Opacity.opacity.value < 0.01, true);
|
|
||||||
|
|
||||||
await tester.pump(const Duration(milliseconds: 300));
|
|
||||||
|
|
||||||
// Page 2 covers page 1.
|
// Page 2 covers page 1.
|
||||||
expect(find.text('Page 1'), findsNothing);
|
expect(find.text('Page 1'), findsNothing);
|
||||||
expect(find.text('Page 2'), isOnstage);
|
expect(find.text('Page 2'), isOnstage);
|
||||||
|
|
||||||
tester.state<NavigatorState>(find.byType(Navigator)).pop();
|
tester.state<NavigatorState>(find.byType(Navigator)).pop();
|
||||||
await tester.pump();
|
await tester.pump();
|
||||||
|
await tester.pump(const Duration(milliseconds: 100));
|
||||||
|
|
||||||
|
widget1Scale = _findForwardScaleTransition(find.text('Page 1'));
|
||||||
|
widget2Scale = _findForwardScaleTransition(find.text('Page 2'));
|
||||||
|
widget2Opacity = _findForwardFadeTransition(find.text('Page 2'));
|
||||||
|
|
||||||
|
// Page 1 is narrowing down, but still larger than 1.0.
|
||||||
|
expect(widget1Scale.scale.value, greaterThan(1.0));
|
||||||
|
// Page 2 is smaller than 1.0.
|
||||||
|
expect(widget2Scale.scale.value, lessThan(1.0));
|
||||||
|
// Page 2 is becoming transparent.
|
||||||
|
expect(widget2Opacity.opacity.value, lessThan(1.0));
|
||||||
|
|
||||||
|
await tester.pump(const Duration(milliseconds: 200));
|
||||||
await tester.pump(const Duration(milliseconds: 1));
|
await tester.pump(const Duration(milliseconds: 1));
|
||||||
|
|
||||||
widget2Opacity =
|
|
||||||
tester.element(find.text('Page 2')).findAncestorWidgetOfExactType<FadeTransition>()!;
|
|
||||||
widget2TopLeft = tester.getTopLeft(find.text('Page 2'));
|
|
||||||
|
|
||||||
// Page 2 starts to move down.
|
|
||||||
expect(widget1TopLeft.dy < widget2TopLeft.dy, true);
|
|
||||||
// Page 2 starts to lose opacity.
|
|
||||||
expect(widget2Opacity.opacity.value < 1.0, true);
|
|
||||||
|
|
||||||
await tester.pump(const Duration(milliseconds: 300));
|
|
||||||
|
|
||||||
expect(find.text('Page 1'), isOnstage);
|
expect(find.text('Page 1'), isOnstage);
|
||||||
expect(find.text('Page 2'), findsNothing);
|
expect(find.text('Page 2'), findsNothing);
|
||||||
},
|
},
|
||||||
@ -155,6 +172,70 @@ void main() {
|
|||||||
skip: kIsWeb, // [intended] no default transitions on the web.
|
skip: kIsWeb, // [intended] no default transitions on the web.
|
||||||
);
|
);
|
||||||
|
|
||||||
|
testWidgets('test page transition with FadeUpwardsPageTransitionBuilder', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
theme: ThemeData(
|
||||||
|
pageTransitionsTheme: const PageTransitionsTheme(
|
||||||
|
builders: <TargetPlatform, PageTransitionsBuilder>{
|
||||||
|
TargetPlatform.android: FadeUpwardsPageTransitionsBuilder(),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
home: const Material(child: Text('Page 1')),
|
||||||
|
routes: <String, WidgetBuilder>{
|
||||||
|
'/next': (BuildContext context) {
|
||||||
|
return const Material(child: Text('Page 2'));
|
||||||
|
},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final Offset widget1TopLeft = tester.getTopLeft(find.text('Page 1'));
|
||||||
|
|
||||||
|
tester.state<NavigatorState>(find.byType(Navigator)).pushNamed('/next');
|
||||||
|
await tester.pump();
|
||||||
|
await tester.pump(const Duration(milliseconds: 1));
|
||||||
|
|
||||||
|
FadeTransition widget2Opacity =
|
||||||
|
tester.element(find.text('Page 2')).findAncestorWidgetOfExactType<FadeTransition>()!;
|
||||||
|
Offset widget2TopLeft = tester.getTopLeft(find.text('Page 2'));
|
||||||
|
final Size widget2Size = tester.getSize(find.text('Page 2'));
|
||||||
|
|
||||||
|
// Android transition is vertical only.
|
||||||
|
expect(widget1TopLeft.dx == widget2TopLeft.dx, true);
|
||||||
|
// Page 1 is above page 2 mid-transition.
|
||||||
|
expect(widget1TopLeft.dy < widget2TopLeft.dy, true);
|
||||||
|
// Animation begins 3/4 of the way up the page.
|
||||||
|
expect(widget2TopLeft.dy < widget2Size.height / 4.0, true);
|
||||||
|
// Animation starts with page 2 being near transparent.
|
||||||
|
expect(widget2Opacity.opacity.value < 0.01, true);
|
||||||
|
|
||||||
|
await tester.pump(const Duration(milliseconds: 300));
|
||||||
|
|
||||||
|
// Page 2 covers page 1.
|
||||||
|
expect(find.text('Page 1'), findsNothing);
|
||||||
|
expect(find.text('Page 2'), isOnstage);
|
||||||
|
|
||||||
|
tester.state<NavigatorState>(find.byType(Navigator)).pop();
|
||||||
|
await tester.pump();
|
||||||
|
await tester.pump(const Duration(milliseconds: 1));
|
||||||
|
|
||||||
|
widget2Opacity =
|
||||||
|
tester.element(find.text('Page 2')).findAncestorWidgetOfExactType<FadeTransition>()!;
|
||||||
|
widget2TopLeft = tester.getTopLeft(find.text('Page 2'));
|
||||||
|
|
||||||
|
// Page 2 starts to move down.
|
||||||
|
expect(widget1TopLeft.dy < widget2TopLeft.dy, true);
|
||||||
|
// Page 2 starts to lose opacity.
|
||||||
|
expect(widget2Opacity.opacity.value < 1.0, true);
|
||||||
|
|
||||||
|
await tester.pump(const Duration(milliseconds: 300));
|
||||||
|
|
||||||
|
expect(find.text('Page 1'), isOnstage);
|
||||||
|
expect(find.text('Page 2'), findsNothing);
|
||||||
|
}, variant: TargetPlatformVariant.only(TargetPlatform.android));
|
||||||
|
|
||||||
testWidgets('test fullscreen dialog transition', (WidgetTester tester) async {
|
testWidgets('test fullscreen dialog transition', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
const MaterialApp(
|
const MaterialApp(
|
||||||
|
@ -66,7 +66,7 @@ void main() {
|
|||||||
skip: kIsWeb, // [intended] no default transitions on the web.
|
skip: kIsWeb, // [intended] no default transitions on the web.
|
||||||
);
|
);
|
||||||
|
|
||||||
testWidgets('Default PageTransitionsTheme builds a _FadeUpwardsPageTransition for android', (WidgetTester tester) async {
|
testWidgets('Default PageTransitionsTheme builds a _ZoomPageTransition for android', (WidgetTester tester) async {
|
||||||
final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{
|
final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{
|
||||||
'/': (BuildContext context) => Material(
|
'/': (BuildContext context) => Material(
|
||||||
child: TextButton(
|
child: TextButton(
|
||||||
@ -83,20 +83,20 @@ void main() {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
Finder findFadeUpwardsPageTransition() {
|
Finder findZoomPageTransition() {
|
||||||
return find.descendant(
|
return find.descendant(
|
||||||
of: find.byType(MaterialApp),
|
of: find.byType(MaterialApp),
|
||||||
matching: find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_FadeUpwardsPageTransition'),
|
matching: find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_ZoomPageTransition'),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
expect(Theme.of(tester.element(find.text('push'))).platform, debugDefaultTargetPlatformOverride);
|
expect(Theme.of(tester.element(find.text('push'))).platform, debugDefaultTargetPlatformOverride);
|
||||||
expect(findFadeUpwardsPageTransition(), findsOneWidget);
|
expect(findZoomPageTransition(), findsOneWidget);
|
||||||
|
|
||||||
await tester.tap(find.text('push'));
|
await tester.tap(find.text('push'));
|
||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
expect(find.text('page b'), findsOneWidget);
|
expect(find.text('page b'), findsOneWidget);
|
||||||
expect(findFadeUpwardsPageTransition(), findsOneWidget);
|
expect(findZoomPageTransition(), findsOneWidget);
|
||||||
},
|
},
|
||||||
variant: TargetPlatformVariant.only(TargetPlatform.android),
|
variant: TargetPlatformVariant.only(TargetPlatform.android),
|
||||||
skip: kIsWeb, // [intended] no default transitions on the web.
|
skip: kIsWeb, // [intended] no default transitions on the web.
|
||||||
@ -145,7 +145,7 @@ void main() {
|
|||||||
skip: kIsWeb, // [intended] no default transitions on the web.
|
skip: kIsWeb, // [intended] no default transitions on the web.
|
||||||
);
|
);
|
||||||
|
|
||||||
testWidgets('PageTransitionsTheme override builds a _ZoomPageTransition', (WidgetTester tester) async {
|
testWidgets('PageTransitionsTheme override builds a _FadeUpwardsTransition', (WidgetTester tester) async {
|
||||||
final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{
|
final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{
|
||||||
'/': (BuildContext context) => Material(
|
'/': (BuildContext context) => Material(
|
||||||
child: TextButton(
|
child: TextButton(
|
||||||
@ -161,7 +161,7 @@ void main() {
|
|||||||
theme: ThemeData(
|
theme: ThemeData(
|
||||||
pageTransitionsTheme: const PageTransitionsTheme(
|
pageTransitionsTheme: const PageTransitionsTheme(
|
||||||
builders: <TargetPlatform, PageTransitionsBuilder>{
|
builders: <TargetPlatform, PageTransitionsBuilder>{
|
||||||
TargetPlatform.android: ZoomPageTransitionsBuilder(), // creates a _ZoomPageTransition
|
TargetPlatform.android: FadeUpwardsPageTransitionsBuilder(), // creates a _FadeUpwardsTransition
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -169,20 +169,20 @@ void main() {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
Finder findZoomPageTransition() {
|
Finder findFadeUpwardsPageTransition() {
|
||||||
return find.descendant(
|
return find.descendant(
|
||||||
of: find.byType(MaterialApp),
|
of: find.byType(MaterialApp),
|
||||||
matching: find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_ZoomPageTransition'),
|
matching: find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_FadeUpwardsPageTransition'),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
expect(Theme.of(tester.element(find.text('push'))).platform, debugDefaultTargetPlatformOverride);
|
expect(Theme.of(tester.element(find.text('push'))).platform, debugDefaultTargetPlatformOverride);
|
||||||
expect(findZoomPageTransition(), findsOneWidget);
|
expect(findFadeUpwardsPageTransition(), findsOneWidget);
|
||||||
|
|
||||||
await tester.tap(find.text('push'));
|
await tester.tap(find.text('push'));
|
||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
expect(find.text('page b'), findsOneWidget);
|
expect(find.text('page b'), findsOneWidget);
|
||||||
expect(findZoomPageTransition(), findsOneWidget);
|
expect(findFadeUpwardsPageTransition(), findsOneWidget);
|
||||||
},
|
},
|
||||||
variant: TargetPlatformVariant.only(TargetPlatform.android),
|
variant: TargetPlatformVariant.only(TargetPlatform.android),
|
||||||
skip: kIsWeb, // [intended] no default transitions on the web.
|
skip: kIsWeb, // [intended] no default transitions on the web.
|
||||||
|
@ -70,6 +70,12 @@ Future<void> pumpTestWidget(
|
|||||||
}
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
// Find the exact transform which is the descendant of [UserAccountsDrawerHeader].
|
||||||
|
final Finder findTransform = find.descendant(
|
||||||
|
of: find.byType(UserAccountsDrawerHeader),
|
||||||
|
matching: find.byType(Transform),
|
||||||
|
);
|
||||||
|
|
||||||
testWidgets('UserAccountsDrawerHeader test', (WidgetTester tester) async {
|
testWidgets('UserAccountsDrawerHeader test', (WidgetTester tester) async {
|
||||||
await pumpTestWidget(tester);
|
await pumpTestWidget(tester);
|
||||||
|
|
||||||
@ -127,7 +133,7 @@ void main() {
|
|||||||
|
|
||||||
testWidgets('UserAccountsDrawerHeader icon rotation test', (WidgetTester tester) async {
|
testWidgets('UserAccountsDrawerHeader icon rotation test', (WidgetTester tester) async {
|
||||||
await pumpTestWidget(tester);
|
await pumpTestWidget(tester);
|
||||||
Transform transformWidget = tester.firstWidget(find.byType(Transform));
|
Transform transformWidget = tester.firstWidget(findTransform);
|
||||||
|
|
||||||
// Icon is right side up.
|
// Icon is right side up.
|
||||||
expect(transformWidget.transform.getRotation()[0], 1.0);
|
expect(transformWidget.transform.getRotation()[0], 1.0);
|
||||||
@ -140,7 +146,7 @@ void main() {
|
|||||||
|
|
||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
await tester.pump();
|
await tester.pump();
|
||||||
transformWidget = tester.firstWidget(find.byType(Transform));
|
transformWidget = tester.firstWidget(findTransform);
|
||||||
|
|
||||||
// Icon has rotated 180 degrees.
|
// Icon has rotated 180 degrees.
|
||||||
expect(transformWidget.transform.getRotation()[0], -1.0);
|
expect(transformWidget.transform.getRotation()[0], -1.0);
|
||||||
@ -153,7 +159,7 @@ void main() {
|
|||||||
|
|
||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
await tester.pump();
|
await tester.pump();
|
||||||
transformWidget = tester.firstWidget(find.byType(Transform));
|
transformWidget = tester.firstWidget(findTransform);
|
||||||
|
|
||||||
// Icon has rotated 180 degrees back to the original position.
|
// Icon has rotated 180 degrees back to the original position.
|
||||||
expect(transformWidget.transform.getRotation()[0], 1.0);
|
expect(transformWidget.transform.getRotation()[0], 1.0);
|
||||||
@ -178,7 +184,7 @@ void main() {
|
|||||||
),
|
),
|
||||||
));
|
));
|
||||||
|
|
||||||
Transform transformWidget = tester.firstWidget(find.byType(Transform));
|
Transform transformWidget = tester.firstWidget(findTransform);
|
||||||
|
|
||||||
// Icon is right side up.
|
// Icon is right side up.
|
||||||
expect(transformWidget.transform.getRotation()[0], 1.0);
|
expect(transformWidget.transform.getRotation()[0], 1.0);
|
||||||
@ -189,7 +195,7 @@ void main() {
|
|||||||
expect(tester.hasRunningAnimations, isFalse);
|
expect(tester.hasRunningAnimations, isFalse);
|
||||||
|
|
||||||
expect(await tester.pumpAndSettle(), 1);
|
expect(await tester.pumpAndSettle(), 1);
|
||||||
transformWidget = tester.firstWidget(find.byType(Transform));
|
transformWidget = tester.firstWidget(findTransform);
|
||||||
|
|
||||||
// Icon has not rotated.
|
// Icon has not rotated.
|
||||||
expect(transformWidget.transform.getRotation()[0], 1.0);
|
expect(transformWidget.transform.getRotation()[0], 1.0);
|
||||||
@ -198,7 +204,7 @@ void main() {
|
|||||||
|
|
||||||
testWidgets('UserAccountsDrawerHeader icon rotation test speeeeeedy', (WidgetTester tester) async {
|
testWidgets('UserAccountsDrawerHeader icon rotation test speeeeeedy', (WidgetTester tester) async {
|
||||||
await pumpTestWidget(tester);
|
await pumpTestWidget(tester);
|
||||||
Transform transformWidget = tester.firstWidget(find.byType(Transform));
|
Transform transformWidget = tester.firstWidget(findTransform);
|
||||||
|
|
||||||
// Icon is right side up.
|
// Icon is right side up.
|
||||||
expect(transformWidget.transform.getRotation()[0], 1.0);
|
expect(transformWidget.transform.getRotation()[0], 1.0);
|
||||||
@ -230,7 +236,7 @@ void main() {
|
|||||||
|
|
||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
await tester.pump();
|
await tester.pump();
|
||||||
transformWidget = tester.firstWidget(find.byType(Transform));
|
transformWidget = tester.firstWidget(findTransform);
|
||||||
|
|
||||||
// Icon has rotated 180 degrees back to the original position.
|
// Icon has rotated 180 degrees back to the original position.
|
||||||
expect(transformWidget.transform.getRotation()[0], 1.0);
|
expect(transformWidget.transform.getRotation()[0], 1.0);
|
||||||
|
@ -728,7 +728,14 @@ Future<void> main() async {
|
|||||||
|
|
||||||
testWidgets('Hero pop transition interrupted by a push', (WidgetTester tester) async {
|
testWidgets('Hero pop transition interrupted by a push', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
MaterialApp(routes: routes),
|
MaterialApp(
|
||||||
|
routes: routes,
|
||||||
|
theme: ThemeData(pageTransitionsTheme: const PageTransitionsTheme(
|
||||||
|
builders: <TargetPlatform, PageTransitionsBuilder>{
|
||||||
|
TargetPlatform.android: FadeUpwardsPageTransitionsBuilder(),
|
||||||
|
},
|
||||||
|
)),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Pushes MaterialPageRoute '/two'.
|
// Pushes MaterialPageRoute '/two'.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user