Fix memory leaks in FloatingActionButton (#146711)

This commit is contained in:
Valentin Vignal 2024-04-14 06:48:25 +08:00 committed by GitHub
parent 46fbb73440
commit 266cdf0b1e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 68 additions and 38 deletions

View file

@ -1320,6 +1320,9 @@ class _FloatingActionButtonTransitionState extends State<_FloatingActionButtonTr
// The animations applied to the Floating Action Button when it is entering or exiting.
// Controls the previous widget.child as it exits.
late AnimationController _previousController;
CurvedAnimation? _previousExitScaleAnimation;
CurvedAnimation? _previousExitRotationCurvedAnimation;
CurvedAnimation? _currentEntranceScaleAnimation;
late Animation<double> _previousScaleAnimation;
late TrainHoppingAnimation _previousRotationAnimation;
// The animations to run, considering the widget's fabMoveAnimation and the current/previous entrance/exit animations.
@ -1352,6 +1355,9 @@ class _FloatingActionButtonTransitionState extends State<_FloatingActionButtonTr
@override
void dispose() {
_previousController.dispose();
_previousExitScaleAnimation?.dispose();
_previousExitRotationCurvedAnimation?.dispose();
_currentEntranceScaleAnimation?.dispose();
_disposeAnimations();
super.dispose();
}
@ -1402,19 +1408,24 @@ class _FloatingActionButtonTransitionState extends State<_FloatingActionButtonTr
}
void _updateAnimations() {
_previousExitScaleAnimation?.dispose();
// Get the animations for exit and entrance.
final CurvedAnimation previousExitScaleAnimation = CurvedAnimation(
_previousExitScaleAnimation = CurvedAnimation(
parent: _previousController,
curve: Curves.easeIn,
);
final Animation<double> previousExitRotationAnimation = Tween<double>(begin: 1.0, end: 1.0).animate(
CurvedAnimation(
_previousExitRotationCurvedAnimation?.dispose();
_previousExitRotationCurvedAnimation = CurvedAnimation(
parent: _previousController,
curve: Curves.easeIn,
),
);
final Animation<double> previousExitRotationAnimation = Tween<double>(begin: 1.0, end: 1.0).animate(
_previousExitRotationCurvedAnimation!
);
final CurvedAnimation currentEntranceScaleAnimation = CurvedAnimation(
_currentEntranceScaleAnimation?.dispose();
_currentEntranceScaleAnimation = CurvedAnimation(
parent: widget.currentController,
curve: Curves.easeIn,
);
@ -1425,8 +1436,8 @@ class _FloatingActionButtonTransitionState extends State<_FloatingActionButtonTr
final Animation<double> moveRotationAnimation = widget.fabMotionAnimator.getRotationAnimation(parent: widget.fabMoveAnimation);
// Aggregate the animations.
_previousScaleAnimation = AnimationMin<double>(moveScaleAnimation, previousExitScaleAnimation);
_currentScaleAnimation = AnimationMin<double>(moveScaleAnimation, currentEntranceScaleAnimation);
_previousScaleAnimation = AnimationMin<double>(moveScaleAnimation, _previousExitScaleAnimation!);
_currentScaleAnimation = AnimationMin<double>(moveScaleAnimation, _currentEntranceScaleAnimation!);
_extendedCurrentScaleAnimation = _currentScaleAnimation.drive(CurveTween(curve: const Interval(0.0, 0.1)));
_previousRotationAnimation = TrainHoppingAnimation(previousExitRotationAnimation, moveRotationAnimation);

View file

@ -11,6 +11,7 @@ library;
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
import '../impeller_test_helpers.dart';
@ -30,7 +31,11 @@ void main() {
);
});
testWidgets('Color filter - sepia', (WidgetTester tester) async {
testWidgets('Color filter - sepia',
// 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 {
const ColorFilter sepia = ColorFilter.matrix(<double>[
0.39, 0.769, 0.189, 0, 0, //
0.349, 0.686, 0.168, 0, 0, //

View file

@ -8,6 +8,7 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
import 'semantics_tester.dart';
@ -2820,7 +2821,10 @@ void main() {
expect(events.length, 2);
}, variant: KeySimulatorTransitModeVariant.all());
testWidgets('Focus traversal does not throw when no focusable is available in a group', (WidgetTester tester) async {
testWidgets('Focus traversal does not throw when no focusable is available in a group',
// 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 {
await tester.pumpWidget(const MaterialApp(home: Scaffold(body: ListTile(title: Text('title')))));
final FocusNode? initialFocus = primaryFocus;
await tester.sendKeyEvent(LogicalKeyboardKey.tab);

View file

@ -4,6 +4,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
class TestItem extends StatelessWidget {
const TestItem({ super.key, required this.item, this.width, this.height });
@ -40,7 +41,10 @@ Widget buildFrame({ int? count, double? width, double? height, Axis? scrollDirec
}
void main() {
testWidgets('SliverPrototypeExtentList.builder test', (WidgetTester tester) async {
testWidgets('SliverPrototypeExtentList.builder test',
// 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 {
await tester.pumpWidget(
MaterialApp(
home: Scaffold(

View file

@ -10,6 +10,7 @@ library;
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
void main() {
testWidgets('Centered text', (WidgetTester tester) async {
@ -188,27 +189,32 @@ void main() {
);
});
testWidgets('Text Fade', (WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(useMaterial3: false),
home: Scaffold(
backgroundColor: Colors.transparent,
body: RepaintBoundary(
child: Center(
child: Container(
width: 200.0,
height: 200.0,
color: Colors.green,
child: Center(
child: Container(
width: 100.0,
color: Colors.blue,
child: const Text(
'Pp PPp PPPp PPPPp PPPPpp PPPPppp PPPPppppp ',
style: TextStyle(color: Colors.black),
maxLines: 3,
overflow: TextOverflow.fade,
testWidgets(
'Text Fade',
// 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 {
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(useMaterial3: false),
home: Scaffold(
backgroundColor: Colors.transparent,
body: RepaintBoundary(
child: Center(
child: Container(
width: 200.0,
height: 200.0,
color: Colors.green,
child: Center(
child: Container(
width: 100.0,
color: Colors.blue,
child: const Text(
'Pp PPp PPPp PPPPp PPPPpp PPPPppp PPPPppppp ',
style: TextStyle(color: Colors.black),
maxLines: 3,
overflow: TextOverflow.fade,
),
),
),
),
@ -216,14 +222,14 @@ void main() {
),
),
),
),
);
);
await expectLater(
find.byType(RepaintBoundary).first,
matchesGoldenFile('text_golden.Fade.png'),
);
});
await expectLater(
find.byType(RepaintBoundary).first,
matchesGoldenFile('text_golden.Fade.png'),
);
},
);
testWidgets('Default Strut text', (WidgetTester tester) async {
await tester.pumpWidget(