Fix memory leaks in open upwards page transition (#148046)

This commit is contained in:
Valentin Vignal 2024-05-15 06:25:58 +08:00 committed by GitHub
parent de9ca5c1c8
commit b23f34657e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 64 additions and 20 deletions

View File

@ -48,7 +48,7 @@ class _FadeUpwardsPageTransition extends StatelessWidget {
}
// This transition is intended to match the default for Android P.
class _OpenUpwardsPageTransition extends StatelessWidget {
class _OpenUpwardsPageTransition extends StatefulWidget {
const _OpenUpwardsPageTransition({
required this.animation,
required this.secondaryAnimation,
@ -81,37 +81,77 @@ class _OpenUpwardsPageTransition extends StatelessWidget {
final Animation<double> secondaryAnimation;
final Widget child;
@override
State<_OpenUpwardsPageTransition> createState() => _OpenUpwardsPageTransitionState();
}
class _OpenUpwardsPageTransitionState extends State<_OpenUpwardsPageTransition> {
late CurvedAnimation _primaryAnimation;
late CurvedAnimation _secondaryTranslationCurvedAnimation;
@override
void initState() {
super.initState();
_setAnimations();
}
@override
void didUpdateWidget(covariant _OpenUpwardsPageTransition oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.animation != widget.animation ||
oldWidget.secondaryAnimation != widget.secondaryAnimation
) {
_disposeAnimations();
_setAnimations();
}
}
void _setAnimations() {
_primaryAnimation = CurvedAnimation(
parent: widget.animation,
curve: _OpenUpwardsPageTransition._transitionCurve,
reverseCurve: _OpenUpwardsPageTransition._transitionCurve.flipped,
);
_secondaryTranslationCurvedAnimation = CurvedAnimation(
parent: widget.secondaryAnimation,
curve: _OpenUpwardsPageTransition._transitionCurve,
reverseCurve: _OpenUpwardsPageTransition._transitionCurve.flipped,
);
}
void _disposeAnimations() {
_primaryAnimation.dispose();
_secondaryTranslationCurvedAnimation.dispose();
}
@override
void dispose() {
_disposeAnimations();
super.dispose();
}
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
final Size size = constraints.biggest;
final CurvedAnimation primaryAnimation = CurvedAnimation(
parent: animation,
curve: _transitionCurve,
reverseCurve: _transitionCurve.flipped,
);
// Gradually expose the new page from bottom to top.
final Animation<double> clipAnimation = Tween<double>(
begin: 0.0,
end: size.height,
).animate(primaryAnimation);
).animate(_primaryAnimation);
final Animation<double> opacityAnimation = _scrimOpacityTween.animate(primaryAnimation);
final Animation<Offset> primaryTranslationAnimation = _primaryTranslationTween.animate(primaryAnimation);
final Animation<double> opacityAnimation = _OpenUpwardsPageTransition._scrimOpacityTween.animate(_primaryAnimation);
final Animation<Offset> primaryTranslationAnimation = _OpenUpwardsPageTransition._primaryTranslationTween.animate(_primaryAnimation);
final Animation<Offset> secondaryTranslationAnimation = _secondaryTranslationTween.animate(
CurvedAnimation(
parent: secondaryAnimation,
curve: _transitionCurve,
reverseCurve: _transitionCurve.flipped,
),
final Animation<Offset> secondaryTranslationAnimation = _OpenUpwardsPageTransition._secondaryTranslationTween.animate(
_secondaryTranslationCurvedAnimation,
);
return AnimatedBuilder(
animation: animation,
animation: widget.animation,
builder: (BuildContext context, Widget? child) {
return Container(
color: Colors.black.withOpacity(opacityAnimation.value),
@ -129,10 +169,10 @@ class _OpenUpwardsPageTransition extends StatelessWidget {
);
},
child: AnimatedBuilder(
animation: secondaryAnimation,
animation: widget.secondaryAnimation,
child: FractionalTranslation(
translation: primaryTranslationAnimation.value,
child: child,
child: widget.child,
),
builder: (BuildContext context, Widget? child) {
return FractionalTranslation(

View File

@ -8,6 +8,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
void main() {
final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized();
@ -97,7 +98,10 @@ void main() {
expect(findZoomPageTransition(), findsOneWidget);
}, variant: TargetPlatformVariant.only(TargetPlatform.android));
testWidgets('PageTransitionsTheme override builds a _OpenUpwardsPageTransition', (WidgetTester tester) async {
testWidgets('PageTransitionsTheme override builds a _OpenUpwardsPageTransition',
// TODO(polina-c): remove when fixed https://github.com/flutter/flutter/issues/145600 [leak-tracking-opt-in]
experimentalLeakTesting: LeakTesting.settings.withTracked(classes: const <String>['CurvedAnimation']),
(WidgetTester tester) async {
final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{
'/': (BuildContext context) => Material(
child: TextButton(