Skip to content

Commit c82ddd3

Browse files
authored
✨ Android Q transition by default (#98559)
1 parent 7208065 commit c82ddd3

9 files changed

+254
-100
lines changed

packages/flutter/lib/src/material/page.dart

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -63,19 +63,24 @@ class MaterialPageRoute<T> extends PageRoute<T> with MaterialRouteTransitionMixi
6363
/// A mixin that provides platform-adaptive transitions for a [PageRoute].
6464
///
6565
/// {@template flutter.material.materialRouteTransitionMixin}
66-
/// For Android, the entrance transition for the page slides the route upwards
67-
/// and fades it in. The exit transition is the same, but in reverse.
68-
///
69-
/// The transition is adaptive to the platform and on iOS, the route slides in
70-
/// from the right and exits in reverse. The route also shifts to the left in
71-
/// parallax when another page enters to cover it. (These directions are flipped
72-
/// in environments with a right-to-left reading direction.)
66+
/// For Android, the entrance transition for the page zooms in and fades in
67+
/// while the exiting page zooms out and fades out. The exit transition is similar,
68+
/// but in reverse.
69+
///
70+
/// For iOS, the page slides in from the right and exits in reverse. The page
71+
/// also shifts to the left in parallax when another page enters to cover it.
72+
/// (These directions are flipped in environments with a right-to-left reading
73+
/// direction.)
7374
/// {@endtemplate}
7475
///
7576
/// See also:
7677
///
7778
/// * [PageTransitionsTheme], which defines the default page transitions used
7879
/// by the [MaterialRouteTransitionMixin.buildTransitions].
80+
/// * [ZoomPageTransitionsBuilder], which is the default page transition used
81+
/// by the [PageTransitionsTheme].
82+
/// * [CupertinoPageTransitionsBuilder], which is the default page transition
83+
/// for iOS and macOS.
7984
mixin MaterialRouteTransitionMixin<T> on PageRoute<T> {
8085
/// Builds the primary contents of the route.
8186
@protected

packages/flutter/lib/src/material/page_transitions_theme.dart

Lines changed: 45 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ import 'colors.dart';
99
import 'theme.dart';
1010

1111
// Slides the page upwards and fades it in, starting from 1/4 screen
12-
// below the top.
12+
// below the top. The transition is intended to match the default for
13+
// Android O.
1314
class _FadeUpwardsPageTransition extends StatelessWidget {
1415
_FadeUpwardsPageTransition({
1516
Key? key,
@@ -146,7 +147,7 @@ class _OpenUpwardsPageTransition extends StatelessWidget {
146147
}
147148

148149
// Zooms and fades a new page in, zooming out the previous page. This transition
149-
// is designed to match the Android 10 activity transition.
150+
// is designed to match the Android Q activity transition.
150151
class _ZoomPageTransition extends StatelessWidget {
151152
/// Creates a [_ZoomPageTransition].
152153
///
@@ -291,16 +292,16 @@ class _ZoomEnterTransition extends StatelessWidget {
291292
@override
292293
Widget build(BuildContext context) {
293294
double opacity = 0;
294-
// The transition's scrim opacity only increases on the forward transition. In the reverse
295-
// transition, the opacity should always be 0.0.
295+
// The transition's scrim opacity only increases on the forward transition.
296+
// In the reverse transition, the opacity should always be 0.0.
296297
//
297-
// Therefore, we need to only apply the scrim opacity animation when the transition
298-
// is running forwards.
298+
// Therefore, we need to only apply the scrim opacity animation when
299+
// the transition is running forwards.
299300
//
300-
// The reason that we check that the animation's status is not `completed` instead
301-
// of checking that it is `forward` is that this allows the interrupted reversal of the
302-
// forward transition to smoothly fade the scrim away. This prevents a disjointed
303-
// removal of the scrim.
301+
// The reason that we check that the animation's status is not `completed`
302+
// instead of checking that it is `forward` is that this allows
303+
// the interrupted reversal of the forward transition to smoothly fade
304+
// the scrim away. This prevents a disjointed removal of the scrim.
304305
if (!reverse && animation.status != AnimationStatus.completed) {
305306
opacity = _scrimOpacityTween.evaluate(animation)!;
306307
}
@@ -317,17 +318,14 @@ class _ZoomEnterTransition extends StatelessWidget {
317318
return AnimatedBuilder(
318319
animation: animation,
319320
builder: (BuildContext context, Widget? child) {
320-
return Container(
321+
return ColoredBox(
321322
color: Colors.black.withOpacity(opacity),
322323
child: child,
323324
);
324325
},
325326
child: FadeTransition(
326327
opacity: fadeTransition,
327-
child: ScaleTransition(
328-
scale: scaleTransition,
329-
child: child,
330-
),
328+
child: ScaleTransition(scale: scaleTransition, child: child),
331329
),
332330
);
333331
}
@@ -374,10 +372,7 @@ class _ZoomExitTransition extends StatelessWidget {
374372

375373
return FadeTransition(
376374
opacity: fadeTransition,
377-
child: ScaleTransition(
378-
scale: scaleTransition,
379-
child: child,
380-
),
375+
child: ScaleTransition(scale: scaleTransition, child: child),
381376
);
382377
}
383378
}
@@ -391,11 +386,12 @@ class _ZoomExitTransition extends StatelessWidget {
391386
///
392387
/// See also:
393388
///
394-
/// * [FadeUpwardsPageTransitionsBuilder], which defines a default page transition.
389+
/// * [FadeUpwardsPageTransitionsBuilder], which defines a page transition
390+
/// that's similar to the one provided by Android O.
395391
/// * [OpenUpwardsPageTransitionsBuilder], which defines a page transition
396392
/// that's similar to the one provided by Android P.
397-
/// * [ZoomPageTransitionsBuilder], which defines a page transition similar
398-
/// to the one provided in Android 10.
393+
/// * [ZoomPageTransitionsBuilder], which defines the default page transition
394+
/// that's similar to the one provided in Android Q.
399395
/// * [CupertinoPageTransitionsBuilder], which defines a horizontal page
400396
/// transition that matches native iOS page transitions.
401397
abstract class PageTransitionsBuilder {
@@ -419,18 +415,19 @@ abstract class PageTransitionsBuilder {
419415
);
420416
}
421417

422-
/// Used by [PageTransitionsTheme] to define a default [MaterialPageRoute] page
423-
/// transition animation.
418+
/// Used by [PageTransitionsTheme] to define a vertically fading
419+
/// [MaterialPageRoute] page transition animation that looks like
420+
/// the default page transition used on Android O.
424421
///
425-
/// The default animation fades the new page in while translating it upwards,
422+
/// The animation fades the new page in while translating it upwards,
426423
/// starting from about 25% below the top of the screen.
427424
///
428425
/// See also:
429426
///
430427
/// * [OpenUpwardsPageTransitionsBuilder], which defines a page transition
431428
/// that's similar to the one provided by Android P.
432-
/// * [ZoomPageTransitionsBuilder], which defines a page transition similar
433-
/// to the one provided in Android 10.
429+
/// * [ZoomPageTransitionsBuilder], which defines the default page transition
430+
/// that's similar to the one provided in Android Q.
434431
/// * [CupertinoPageTransitionsBuilder], which defines a horizontal page
435432
/// transition that matches native iOS page transitions.
436433
class FadeUpwardsPageTransitionsBuilder extends PageTransitionsBuilder {
@@ -455,9 +452,10 @@ class FadeUpwardsPageTransitionsBuilder extends PageTransitionsBuilder {
455452
///
456453
/// See also:
457454
///
458-
/// * [FadeUpwardsPageTransitionsBuilder], which defines a default page transition.
459-
/// * [ZoomPageTransitionsBuilder], which defines a page transition similar
460-
/// to the one provided in Android 10.
455+
/// * [FadeUpwardsPageTransitionsBuilder], which defines a page transition
456+
/// that's similar to the one provided by Android O.
457+
/// * [ZoomPageTransitionsBuilder], which defines the default page transition
458+
/// that's similar to the one provided in Android Q.
461459
/// * [CupertinoPageTransitionsBuilder], which defines a horizontal page
462460
/// transition that matches native iOS page transitions.
463461
class OpenUpwardsPageTransitionsBuilder extends PageTransitionsBuilder {
@@ -483,18 +481,19 @@ class OpenUpwardsPageTransitionsBuilder extends PageTransitionsBuilder {
483481

484482
/// Used by [PageTransitionsTheme] to define a zooming [MaterialPageRoute] page
485483
/// transition animation that looks like the default page transition used on
486-
/// Android 10.
484+
/// Android Q.
487485
///
488486
/// See also:
489487
///
490-
/// * [FadeUpwardsPageTransitionsBuilder], which defines a default page transition.
488+
/// * [FadeUpwardsPageTransitionsBuilder], which defines a page transition
489+
/// that's similar to the one provided by Android O.
491490
/// * [OpenUpwardsPageTransitionsBuilder], which defines a page transition
492-
/// similar to the one provided by Android P.
491+
/// that's similar to the one provided by Android P.
493492
/// * [CupertinoPageTransitionsBuilder], which defines a horizontal page
494493
/// transition that matches native iOS page transitions.
495494
class ZoomPageTransitionsBuilder extends PageTransitionsBuilder {
496495
/// Constructs a page transition animation that matches the transition used on
497-
/// Android 10.
496+
/// Android Q.
498497
const ZoomPageTransitionsBuilder();
499498

500499
@override
@@ -518,11 +517,12 @@ class ZoomPageTransitionsBuilder extends PageTransitionsBuilder {
518517
///
519518
/// See also:
520519
///
521-
/// * [FadeUpwardsPageTransitionsBuilder], which defines a default page transition.
520+
/// * [FadeUpwardsPageTransitionsBuilder], which defines a page transition
521+
/// that's similar to the one provided by Android O.
522522
/// * [OpenUpwardsPageTransitionsBuilder], which defines a page transition
523523
/// that's similar to the one provided by Android P.
524-
/// * [ZoomPageTransitionsBuilder], which defines a page transition similar
525-
/// to the one provided in Android 10.
524+
/// * [ZoomPageTransitionsBuilder], which defines the default page transition
525+
/// that's similar to the one provided in Android Q.
526526
class CupertinoPageTransitionsBuilder extends PageTransitionsBuilder {
527527
/// Constructs a page transition animation that matches the iOS transition.
528528
const CupertinoPageTransitionsBuilder();
@@ -553,34 +553,35 @@ class CupertinoPageTransitionsBuilder extends PageTransitionsBuilder {
553553
///
554554
/// * [ThemeData.pageTransitionsTheme], which defines the default page
555555
/// transitions for the overall theme.
556-
/// * [FadeUpwardsPageTransitionsBuilder], which defines a default page transition.
556+
/// * [FadeUpwardsPageTransitionsBuilder], which defines a page transition
557+
/// that's similar to the one provided by Android O.
557558
/// * [OpenUpwardsPageTransitionsBuilder], which defines a page transition
558559
/// that's similar to the one provided by Android P.
560+
/// * [ZoomPageTransitionsBuilder], which defines the default page transition
561+
/// that's similar to the one provided by Android Q.
559562
/// * [CupertinoPageTransitionsBuilder], which defines a horizontal page
560563
/// transition that matches native iOS page transitions.
561564
@immutable
562565
class PageTransitionsTheme with Diagnosticable {
563566
/// Constructs an object that selects a transition based on the platform.
564567
///
565-
/// By default the list of builders is: [FadeUpwardsPageTransitionsBuilder]
568+
/// By default the list of builders is: [ZoomPageTransitionsBuilder]
566569
/// for [TargetPlatform.android], and [CupertinoPageTransitionsBuilder] for
567570
/// [TargetPlatform.iOS] and [TargetPlatform.macOS].
568571
const PageTransitionsTheme({ Map<TargetPlatform, PageTransitionsBuilder> builders = _defaultBuilders }) : _builders = builders;
569572

570573
static const Map<TargetPlatform, PageTransitionsBuilder> _defaultBuilders = <TargetPlatform, PageTransitionsBuilder>{
571-
TargetPlatform.android: FadeUpwardsPageTransitionsBuilder(),
574+
TargetPlatform.android: ZoomPageTransitionsBuilder(),
572575
TargetPlatform.iOS: CupertinoPageTransitionsBuilder(),
573-
TargetPlatform.linux: FadeUpwardsPageTransitionsBuilder(),
574576
TargetPlatform.macOS: CupertinoPageTransitionsBuilder(),
575-
TargetPlatform.windows: FadeUpwardsPageTransitionsBuilder(),
576577
};
577578

578579
/// The [PageTransitionsBuilder]s supported by this theme.
579580
Map<TargetPlatform, PageTransitionsBuilder> get builders => _builders;
580581
final Map<TargetPlatform, PageTransitionsBuilder> _builders;
581582

582583
/// Delegates to the builder for the current [ThemeData.platform]
583-
/// or [FadeUpwardsPageTransitionsBuilder].
584+
/// or [ZoomPageTransitionsBuilder].
584585
///
585586
/// [MaterialPageRoute.buildTransitions] delegates to this method.
586587
Widget buildTransitions<T>(
@@ -596,7 +597,7 @@ class PageTransitionsTheme with Diagnosticable {
596597
platform = TargetPlatform.iOS;
597598

598599
final PageTransitionsBuilder matchingBuilder =
599-
builders[platform] ?? const FadeUpwardsPageTransitionsBuilder();
600+
builders[platform] ?? const ZoomPageTransitionsBuilder();
600601
return matchingBuilder.buildTransitions<T>(route, context, animation, secondaryAnimation, child);
601602
}
602603

packages/flutter/test/material/bottom_navigation_bar_theme_test.dart

Lines changed: 42 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -151,13 +151,27 @@ void main() {
151151
),
152152
);
153153

154+
final Finder findACTransform = find.descendant(
155+
of: find.byType(BottomNavigationBar),
156+
matching: find.ancestor(
157+
of: find.text('AC'),
158+
matching: find.byType(Transform),
159+
),
160+
);
161+
final Finder findAlarmTransform = find.descendant(
162+
of: find.byType(BottomNavigationBar),
163+
matching: find.ancestor(
164+
of: find.text('Alarm'),
165+
matching: find.byType(Transform),
166+
),
167+
);
154168
final TextStyle selectedFontStyle = tester.renderObject<RenderParagraph>(find.text('AC')).text.style!;
155169
final TextStyle selectedIcon = _iconStyle(tester, Icons.ac_unit);
156170
final TextStyle unselectedIcon = _iconStyle(tester, Icons.access_alarm);
157171
expect(selectedFontStyle.fontSize, selectedFontStyle.fontSize);
158172
// Unselected label has a font size of 22 but is scaled down to be font size 21.
159173
expect(
160-
tester.firstWidget<Transform>(find.ancestor(of: find.text('Alarm'), matching: find.byType(Transform))).transform,
174+
tester.firstWidget<Transform>(findAlarmTransform).transform,
161175
equals(Matrix4.diagonal3(Vector3.all(unselectedTextStyle.fontSize! / selectedTextStyle.fontSize!))),
162176
);
163177
expect(selectedIcon.color, equals(selectedItemColor));
@@ -179,14 +193,8 @@ void main() {
179193
expect(_material(tester).elevation, equals(elevation));
180194
expect(_material(tester).color, equals(backgroundColor));
181195

182-
final Offset selectedBarItem = tester.getCenter(
183-
find.ancestor(of: find.text('AC'),
184-
matching: find.byType(Transform))
185-
);
186-
final Offset unselectedBarItem = tester.getCenter(
187-
find.ancestor(of: find.text('Alarm'),
188-
matching: find.byType(Transform))
189-
);
196+
final Offset selectedBarItem = tester.getCenter(findACTransform);
197+
final Offset unselectedBarItem = tester.getCenter(findAlarmTransform);
190198
final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse);
191199
await gesture.addPointer();
192200
addTearDown(gesture.removePointer);
@@ -270,13 +278,27 @@ void main() {
270278
),
271279
);
272280

281+
Finder findDescendantOfBottomNavigationBar(Finder finder) {
282+
return find.descendant(
283+
of: find.byType(BottomNavigationBar),
284+
matching: finder,
285+
);
286+
}
287+
273288
final TextStyle selectedFontStyle = tester.renderObject<RenderParagraph>(find.text('AC')).text.style!;
274289
final TextStyle selectedIcon = _iconStyle(tester, Icons.ac_unit);
275290
final TextStyle unselectedIcon = _iconStyle(tester, Icons.access_alarm);
276291
expect(selectedFontStyle.fontSize, selectedFontStyle.fontSize);
277292
// Unselected label has a font size of 22 but is scaled down to be font size 21.
278293
expect(
279-
tester.firstWidget<Transform>(find.ancestor(of: find.text('Alarm'), matching: find.byType(Transform))).transform,
294+
tester.firstWidget<Transform>(
295+
findDescendantOfBottomNavigationBar(
296+
find.ancestor(
297+
of: find.text('Alarm'),
298+
matching: find.byType(Transform),
299+
),
300+
),
301+
).transform,
280302
equals(Matrix4.diagonal3(Vector3.all(unselectedTextStyle.fontSize! / selectedTextStyle.fontSize!))),
281303
);
282304
expect(selectedIcon.color, equals(selectedItemColor));
@@ -285,22 +307,24 @@ void main() {
285307
expect(unselectedIcon.fontSize, equals(unselectedIconTheme.size));
286308
// There should not be any [Opacity] or [FadeTransition] widgets
287309
// since showUnselectedLabels and showSelectedLabels are true.
288-
final Finder findOpacity = find.descendant(
289-
of: find.byType(BottomNavigationBar),
290-
matching: find.byType(Opacity),
310+
final Finder findOpacity = findDescendantOfBottomNavigationBar(
311+
find.byType(Opacity),
291312
);
292-
final Finder findFadeTransition = find.descendant(
293-
of: find.byType(BottomNavigationBar),
294-
matching: find.byType(FadeTransition),
313+
final Finder findFadeTransition = findDescendantOfBottomNavigationBar(
314+
find.byType(FadeTransition),
295315
);
296316
expect(findOpacity, findsNothing);
297317
expect(findFadeTransition, findsNothing);
298318
expect(_material(tester).elevation, equals(elevation));
299319
expect(_material(tester).color, equals(backgroundColor));
300320

301321
final Offset barItem = tester.getCenter(
302-
find.ancestor(of: find.text('AC'),
303-
matching: find.byType(Transform))
322+
findDescendantOfBottomNavigationBar(
323+
find.ancestor(
324+
of: find.text('AC'),
325+
matching: find.byType(Transform),
326+
),
327+
),
304328
);
305329
final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse);
306330
await gesture.addPointer();

0 commit comments

Comments
 (0)