flutter/examples/api/test/widgets/routes/flexible_route_transitions.0_test.dart
Mitchell Goodwin d877d2875e
Allow mixing route transitions in one app. (#150031)
Fixes #33799

Allows for a route to inform the route below it in the navigation stack how to animate when the topmost route enters are leaves the stack.

It does this by making a `DelegatedTransition` available for the previous route to look up and use. If available, the route lower in the stack will wrap it's transition builders with that delegated transition and use it instead of it's default secondary transition.

This is what the sample code in this PR shows an app that is able to use both a Material zoom transition and a Cupertino slide transition in one app. It also includes a custom vertical transition. Every page animates off the screen in a way to match up with the incoming page's transition. When popped, the correct transitions play in reverse.

https://github.com/user-attachments/assets/1fc910fa-8cde-4e05-898e-daad8ff4a697

The below video shows this logic making a pseudo iOS styled sheet transition.

https://github.com/flutter/flutter/assets/58190796/207163d8-d87f-48b1-aad9-7e770d1d96c5

All existing page transitions in Flutter will be overwritten by the incoming route if a `delegatedTransition` is provided. This can be opted out of through `canTransitionTo` for a new route widget. Of Flutter's existing page transitions, this PR only adds a `DelegatedTransition` for the Zoom and Cupertino transitions. The other transitions possible in Material will get delegated transitions in a later PR.
2024-10-02 20:08:11 +00:00

60 lines
2.2 KiB
Dart

// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter_api_samples/widgets/routes/flexible_route_transitions.0.dart' as example;
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('Flexible Transitions App is able to build', (WidgetTester tester) async {
await tester.pumpWidget(
const example.FlexibleRouteTransitionsApp(),
);
expect(find.text('Zoom Page'), findsOneWidget);
expect(find.text('Zoom Transition'), findsOneWidget);
expect(find.text('Crazy Vertical Transition'), findsOneWidget);
expect(find.text('Cupertino Transition'), findsOneWidget);
await tester.tap(find.text('Cupertino Transition'));
await tester.pumpAndSettle();
expect(find.text('Zoom Page'), findsNothing);
expect(find.text('Cupertino Page'), findsOneWidget);
});
testWidgets('A vertical slide animation is passed to the previous route', (WidgetTester tester) async {
await tester.pumpWidget(
const example.FlexibleRouteTransitionsApp(),
);
expect(find.text('Zoom Page'), findsOneWidget);
// Save the Y coordinate of the page title.
double lastYPosition = tester.getTopLeft(find.text('Zoom Page')).dy;
await tester.tap(find.text('Crazy Vertical Transition'));
await tester.pump();
await tester.pump(const Duration(milliseconds: 10));
// The current Y coordinate of the page title should be lower than it was
// before as the page slides upwards.
expect(tester.getTopLeft(find.text('Zoom Page')).dy, lessThan(lastYPosition));
lastYPosition = tester.getTopLeft(find.text('Zoom Page')).dy;
await tester.pump(const Duration(milliseconds: 10));
expect(tester.getTopLeft(find.text('Zoom Page')).dy, lessThan(lastYPosition));
lastYPosition = tester.getTopLeft(find.text('Zoom Page')).dy;
await tester.pump(const Duration(milliseconds: 10));
expect(tester.getTopLeft(find.text('Zoom Page')).dy, lessThan(lastYPosition));
lastYPosition = tester.getTopLeft(find.text('Zoom Page')).dy;
await tester.pumpAndSettle();
expect(find.text('Crazy Vertical Page'), findsOneWidget);
});
}