Skip to content

Commit a7fe536

Browse files
[framework] re-rasterize when window size or insets changes (#113647)
1 parent 15a4b00 commit a7fe536

File tree

2 files changed

+76
-0
lines changed

2 files changed

+76
-0
lines changed

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

+33
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,7 @@ class _ZoomEnterTransitionState extends State<_ZoomEnterTransition> with _ZoomTr
291291
bool get useSnapshot => !kIsWeb && widget.allowSnapshotting;
292292

293293
late _ZoomEnterTransitionPainter delegate;
294+
MediaQueryData? mediaQueryData;
294295

295296
static final Animatable<double> _fadeInTransition = Tween<double>(
296297
begin: 0.0,
@@ -355,6 +356,18 @@ class _ZoomEnterTransitionState extends State<_ZoomEnterTransition> with _ZoomTr
355356
super.didUpdateWidget(oldWidget);
356357
}
357358

359+
@override
360+
void didChangeDependencies() {
361+
// If the screen size changes during the transition, perhaps due to
362+
// a keyboard dismissal, then ensure that contents are re-rasterized once.
363+
final MediaQueryData? data = MediaQuery.maybeOf(context);
364+
if (mediaQueryDataChanged(mediaQueryData, data)) {
365+
controller.clear();
366+
}
367+
mediaQueryData = data;
368+
super.didChangeDependencies();
369+
}
370+
358371
@override
359372
void dispose() {
360373
widget.animation.removeListener(onAnimationValueChange);
@@ -394,6 +407,7 @@ class _ZoomExitTransition extends StatefulWidget {
394407

395408
class _ZoomExitTransitionState extends State<_ZoomExitTransition> with _ZoomTransitionBase {
396409
late _ZoomExitTransitionPainter delegate;
410+
MediaQueryData? mediaQueryData;
397411

398412
// See SnapshotWidget doc comment, this is disabled on web because the HTML backend doesn't
399413
// support this functionality and the canvaskit backend uses a single thread for UI and raster
@@ -458,6 +472,18 @@ class _ZoomExitTransitionState extends State<_ZoomExitTransition> with _ZoomTran
458472
super.didUpdateWidget(oldWidget);
459473
}
460474

475+
@override
476+
void didChangeDependencies() {
477+
// If the screen size changes during the transition, perhaps due to
478+
// a keyboard dismissal, then ensure that contents are re-rasterized once.
479+
final MediaQueryData? data = MediaQuery.maybeOf(context);
480+
if (mediaQueryDataChanged(mediaQueryData, data)) {
481+
controller.clear();
482+
}
483+
mediaQueryData = data;
484+
super.didChangeDependencies();
485+
}
486+
461487
@override
462488
void dispose() {
463489
widget.animation.removeListener(onAnimationValueChange);
@@ -804,6 +830,13 @@ mixin _ZoomTransitionBase {
804830
break;
805831
}
806832
}
833+
834+
// Whether any of the properties that would impact the page transition
835+
// changed.
836+
bool mediaQueryDataChanged(MediaQueryData? oldData, MediaQueryData? newData) {
837+
return oldData?.size != newData?.size ||
838+
oldData?.viewInsets != newData?.viewInsets;
839+
}
807840
}
808841

809842
class _ZoomEnterTransitionPainter extends SnapshotPainter {

packages/flutter/test/material/page_test.dart

+43
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5+
@Tags(<String>['reduced-test-set'])
56
import 'package:flutter/cupertino.dart' show CupertinoPageRoute;
7+
import 'package:flutter/foundation.dart';
68
import 'package:flutter/material.dart';
79
import 'package:flutter/rendering.dart';
810
import 'package:flutter_test/flutter_test.dart';
@@ -234,6 +236,47 @@ void main() {
234236
expect(find.text('Page 2'), findsNothing);
235237
}, variant: TargetPlatformVariant.only(TargetPlatform.android));
236238

239+
testWidgets('test page transition (_ZoomPageTransition) with rasterization re-rasterizes when window size changes', (WidgetTester tester) async {
240+
// Shrink the window size.
241+
late Size oldSize;
242+
try {
243+
oldSize = tester.binding.window.physicalSize;
244+
tester.binding.window.physicalSizeTestValue = const Size(1000, 1000);
245+
246+
final Key key = GlobalKey();
247+
await tester.pumpWidget(
248+
RepaintBoundary(
249+
key: key,
250+
child: MaterialApp(
251+
onGenerateRoute: (RouteSettings settings) {
252+
return MaterialPageRoute<void>(
253+
builder: (BuildContext context) {
254+
return const Material(child: SizedBox.shrink());
255+
},
256+
);
257+
},
258+
),
259+
),
260+
);
261+
262+
tester.state<NavigatorState>(find.byType(Navigator)).pushNamed('/next');
263+
await tester.pump();
264+
await tester.pump(const Duration(milliseconds: 50));
265+
266+
await expectLater(find.byKey(key), matchesGoldenFile('zoom_page_transition.small.png'));
267+
268+
// Increase the window size.
269+
tester.binding.window.physicalSizeTestValue = const Size(1000, 2000);
270+
271+
await tester.pump();
272+
await tester.pump(const Duration(milliseconds: 50));
273+
274+
await expectLater(find.byKey(key), matchesGoldenFile('zoom_page_transition.big.png'));
275+
} finally {
276+
tester.binding.window.physicalSizeTestValue = oldSize;
277+
}
278+
}, variant: TargetPlatformVariant.only(TargetPlatform.android), skip: kIsWeb); // [intended] rasterization is not used on the web.
279+
237280
testWidgets('test fullscreen dialog transition', (WidgetTester tester) async {
238281
await tester.pumpWidget(
239282
const MaterialApp(

0 commit comments

Comments
 (0)