Skip to content

Commit 73bf206

Browse files
CupertinoDialogRoute leak fix (#148774)
1 parent 9d7d218 commit 73bf206

File tree

2 files changed

+76
-18
lines changed

2 files changed

+76
-18
lines changed

packages/flutter/lib/src/cupertino/route.dart

Lines changed: 46 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1245,23 +1245,7 @@ final Animatable<double> _dialogScaleTween = Tween<double>(begin: 1.3, end: 1.0)
12451245
.chain(CurveTween(curve: Curves.linearToEaseOut));
12461246

12471247
Widget _buildCupertinoDialogTransitions(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child) {
1248-
final CurvedAnimation fadeAnimation = CurvedAnimation(
1249-
parent: animation,
1250-
curve: Curves.easeInOut,
1251-
);
1252-
if (animation.status == AnimationStatus.reverse) {
1253-
return FadeTransition(
1254-
opacity: fadeAnimation,
1255-
child: child,
1256-
);
1257-
}
1258-
return FadeTransition(
1259-
opacity: fadeAnimation,
1260-
child: ScaleTransition(
1261-
scale: animation.drive(_dialogScaleTween),
1262-
child: child,
1263-
),
1264-
);
1248+
return child;
12651249
}
12661250

12671251
/// Displays an iOS-style dialog above the current contents of the app, with
@@ -1388,14 +1372,58 @@ class CupertinoDialogRoute<T> extends RawDialogRoute<T> {
13881372
String? barrierLabel,
13891373
// This transition duration was eyeballed comparing with iOS
13901374
super.transitionDuration = const Duration(milliseconds: 250),
1391-
super.transitionBuilder = _buildCupertinoDialogTransitions,
1375+
this.transitionBuilder,
13921376
super.settings,
13931377
super.anchorPoint,
13941378
}) : super(
13951379
pageBuilder: (BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
13961380
return builder(context);
13971381
},
1382+
transitionBuilder: transitionBuilder ?? _buildCupertinoDialogTransitions,
13981383
barrierLabel: barrierLabel ?? CupertinoLocalizations.of(context).modalBarrierDismissLabel,
13991384
barrierColor: barrierColor ?? CupertinoDynamicColor.resolve(kCupertinoModalBarrierColor, context),
14001385
);
1386+
1387+
/// Custom transition builder
1388+
RouteTransitionsBuilder? transitionBuilder;
1389+
1390+
CurvedAnimation? _fadeAnimation;
1391+
1392+
@override
1393+
Widget buildTransitions(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child) {
1394+
1395+
if (transitionBuilder != null) {
1396+
return super.buildTransitions(context, animation, secondaryAnimation, child);
1397+
}
1398+
1399+
if (_fadeAnimation?.parent != animation) {
1400+
_fadeAnimation?.dispose();
1401+
_fadeAnimation = CurvedAnimation(
1402+
parent: animation,
1403+
curve: Curves.easeInOut,
1404+
);
1405+
}
1406+
1407+
final CurvedAnimation fadeAnimation = _fadeAnimation!;
1408+
1409+
if (animation.status == AnimationStatus.reverse) {
1410+
return FadeTransition(
1411+
opacity: fadeAnimation,
1412+
child: super.buildTransitions(context, animation, secondaryAnimation, child),
1413+
);
1414+
}
1415+
return FadeTransition(
1416+
opacity: fadeAnimation,
1417+
child: ScaleTransition(
1418+
scale: animation.drive(_dialogScaleTween),
1419+
child: super.buildTransitions(context, animation, secondaryAnimation, child),
1420+
),
1421+
);
1422+
}
1423+
1424+
@override
1425+
void dispose() {
1426+
_fadeAnimation?.dispose();
1427+
super.dispose();
1428+
}
14011429
}

packages/flutter/test/cupertino/route_test.dart

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2696,6 +2696,36 @@ void main() {
26962696
await tester.tap(find.text('tap'));
26972697
await tester.pumpAndSettle();
26982698
});
2699+
2700+
testWidgets('CupertinoDialogRoute does not leak CurveAnimation',
2701+
// TODO(polina-c): remove when fixed https://github.com/flutter/flutter/issues/145600 [leak-tracking-opt-in]
2702+
experimentalLeakTesting: LeakTesting.settings.withTracked(classes: <String>['CurvedAnimation']),
2703+
(WidgetTester tester) async {
2704+
await tester.pumpWidget(MaterialApp(
2705+
home: Navigator(
2706+
onGenerateRoute: (RouteSettings settings) {
2707+
return PageRouteBuilder<dynamic>(
2708+
pageBuilder: (BuildContext context, Animation<double> _, Animation<double> __) {
2709+
return GestureDetector(
2710+
onTap: () async {
2711+
await showCupertinoDialog<void>(
2712+
context: context,
2713+
useRootNavigator: false,
2714+
builder: (BuildContext context) => const SizedBox(),
2715+
);
2716+
},
2717+
child: const Text('tap'),
2718+
);
2719+
},
2720+
);
2721+
},
2722+
),
2723+
));
2724+
2725+
// Open the dialog.
2726+
await tester.tap(find.text('tap'));
2727+
await tester.pumpAndSettle();
2728+
});
26992729
}
27002730

27012731
class MockNavigatorObserver extends NavigatorObserver {

0 commit comments

Comments
 (0)