Skip to content

Commit

Permalink
fixes SearchAnchor leak (#147652)
Browse files Browse the repository at this point in the history
  • Loading branch information
Dimilkalathiya authored May 3, 2024
1 parent c0be3a3 commit c1cafcc
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 25 deletions.
76 changes: 52 additions & 24 deletions packages/flutter/lib/src/material/search_anchor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,8 @@ class _SearchViewRoute extends PopupRoute<_SearchViewRoute> {
final CapturedThemes capturedThemes;
final TextInputAction? textInputAction;
final TextInputType? keyboardType;
CurvedAnimation? curvedAnimation;
CurvedAnimation? viewFadeOnIntervalCurve;

@override
Color? get barrierColor => Colors.transparent;
Expand Down Expand Up @@ -561,6 +563,13 @@ class _SearchViewRoute extends PopupRoute<_SearchViewRoute> {
return super.didPop(result);
}

@override
void dispose() {
curvedAnimation?.dispose();
viewFadeOnIntervalCurve?.dispose();
super.dispose();
}

void updateViewConfig(BuildContext context) {
viewDefaults = _SearchViewDefaultsM3(context, isFullScreen: showFullScreenView);
viewTheme = SearchViewTheme.of(context);
Expand Down Expand Up @@ -620,23 +629,25 @@ class _SearchViewRoute extends PopupRoute<_SearchViewRoute> {
child: AnimatedBuilder(
animation: animation,
builder: (BuildContext context, Widget? child) {
final Animation<double> curvedAnimation = CurvedAnimation(
curvedAnimation ??= CurvedAnimation(
parent: animation,
curve: Curves.easeInOutCubicEmphasized,
reverseCurve: Curves.easeInOutCubicEmphasized.flipped,
);

final Rect viewRect = _rectTween.evaluate(curvedAnimation)!;
final Rect viewRect = _rectTween.evaluate(curvedAnimation!)!;
final double topPadding = showFullScreenView
? lerpDouble(0.0, MediaQuery.paddingOf(context).top, curvedAnimation.value)!
? lerpDouble(0.0, MediaQuery.paddingOf(context).top, curvedAnimation!.value)!
: 0.0;

viewFadeOnIntervalCurve ??= CurvedAnimation(
parent: animation,
curve: _kViewFadeOnInterval,
reverseCurve: _kViewFadeOnInterval.flipped,
);

return FadeTransition(
opacity: CurvedAnimation(
parent: animation,
curve: _kViewFadeOnInterval,
reverseCurve: _kViewFadeOnInterval.flipped,
),
opacity: viewFadeOnIntervalCurve!,
child: capturedThemes.wrap(
_ViewContent(
viewOnChanged: viewOnChanged,
Expand All @@ -654,7 +665,7 @@ class _SearchViewRoute extends PopupRoute<_SearchViewRoute> {
viewHeaderHintStyle: viewHeaderHintStyle,
dividerColor: dividerColor,
showFullScreenView: showFullScreenView,
animation: curvedAnimation,
animation: curvedAnimation!,
topPadding: topPadding,
viewMaxWidth: _rectTween.end!.width,
viewRect: viewRect,
Expand Down Expand Up @@ -738,6 +749,9 @@ class _ViewContent extends StatefulWidget {
class _ViewContentState extends State<_ViewContent> {
Size? _screenSize;
late Rect _viewRect;
late CurvedAnimation viewIconsFadeCurve;
late CurvedAnimation viewDividerFadeCurve;
late CurvedAnimation viewListFadeOnIntervalCurve;
late final SearchController _controller;
Iterable<Widget> result = <Widget>[];
String? searchValue;
Expand All @@ -749,6 +763,7 @@ class _ViewContentState extends State<_ViewContent> {
_viewRect = widget.viewRect;
_controller = widget.searchController;
_controller.addListener(updateSuggestions);
_setupAnimations();
}

@override
Expand Down Expand Up @@ -787,11 +802,36 @@ class _ViewContentState extends State<_ViewContent> {
@override
void dispose() {
_controller.removeListener(updateSuggestions);
_disposeAnimations();
_timer?.cancel();
_timer = null;
super.dispose();
}

void _setupAnimations() {
viewIconsFadeCurve = CurvedAnimation(
parent: widget.animation,
curve: _kViewIconsFadeOnInterval,
reverseCurve: _kViewIconsFadeOnInterval.flipped,
);
viewDividerFadeCurve = CurvedAnimation(
parent: widget.animation,
curve: _kViewDividerFadeOnInterval,
reverseCurve: _kViewFadeOnInterval.flipped,
);
viewListFadeOnIntervalCurve = CurvedAnimation(
parent: widget.animation,
curve: _kViewListFadeOnInterval,
reverseCurve: _kViewListFadeOnInterval.flipped,
);
}

void _disposeAnimations() {
viewIconsFadeCurve.dispose();
viewDividerFadeCurve.dispose();
viewListFadeOnIntervalCurve.dispose();
}

Widget viewBuilder(Iterable<Widget> suggestions) {
if (widget.viewBuilder == null) {
return MediaQuery.removePadding(
Expand Down Expand Up @@ -900,11 +940,7 @@ class _ViewContentState extends State<_ViewContent> {
maxWidth: math.min(widget.viewMaxWidth, _screenSize!.width),
minWidth: 0,
child: FadeTransition(
opacity: CurvedAnimation(
parent: widget.animation,
curve: _kViewIconsFadeOnInterval,
reverseCurve: _kViewIconsFadeOnInterval.flipped,
),
opacity: viewIconsFadeCurve,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Expand Down Expand Up @@ -937,19 +973,11 @@ class _ViewContentState extends State<_ViewContent> {
),
),
FadeTransition(
opacity: CurvedAnimation(
parent: widget.animation,
curve: _kViewDividerFadeOnInterval,
reverseCurve: _kViewFadeOnInterval.flipped,
),
opacity: viewDividerFadeCurve,
child: viewDivider),
Expanded(
child: FadeTransition(
opacity: CurvedAnimation(
parent: widget.animation,
curve: _kViewListFadeOnInterval,
reverseCurve: _kViewListFadeOnInterval.flipped,
),
opacity: viewListFadeOnIntervalCurve,
child: viewBuilder(result),
),
),
Expand Down
6 changes: 5 additions & 1 deletion packages/flutter/test/material/search_anchor_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import 'package:flutter/gestures.dart';
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 '../widgets/semantics_tester.dart';

Expand Down Expand Up @@ -898,7 +899,10 @@ void main() {
expect(textField.textCapitalization, TextCapitalization.none);
});

testWidgets('SearchAnchor respects viewOnChanged and viewOnSubmitted properties', (WidgetTester tester) async {
testWidgets('SearchAnchor respects viewOnChanged and viewOnSubmitted properties',
// 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 SearchController controller = SearchController();
addTearDown(controller.dispose);
int onChangedCalled = 0;
Expand Down

0 comments on commit c1cafcc

Please sign in to comment.