Skip to content

Fix memory leak in CurvedAnimation [Flutter core] #350

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/dropdown_button2/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
- Remove 'must be non-null' and 'must not be null' comments [Flutter core].
- Form fields onChange callback should be called on reset [Flutter core].
- Implement switch expressions.
- Fix memory leak in CurvedAnimation [Flutter core].

## 3.0.0-beta.21

Expand Down
4 changes: 2 additions & 2 deletions packages/dropdown_button2/lib/src/dropdown_menu.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ class _DropdownMenu<T> extends StatefulWidget {
}

class _DropdownMenuState<T> extends State<_DropdownMenu<T>> {
late CurvedAnimation _fadeOpacity;
late CurvedAnimation _resize;
late final CurvedAnimation _fadeOpacity;
late final CurvedAnimation _resize;
late List<Widget> _children;
late SearchMatchFn<T> _searchMatchFn;

Expand Down
50 changes: 41 additions & 9 deletions packages/dropdown_button2/lib/src/dropdown_menu_item.dart
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,46 @@ class _DropdownItemButton<T> extends StatefulWidget {
}

class _DropdownItemButtonState<T> extends State<_DropdownItemButton<T>> {
late CurvedAnimation _opacityAnimation;

@override
void initState() {
super.initState();
_setOpacityAnimation();
}

@override
void didUpdateWidget(_DropdownItemButton<T> oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.itemIndex != widget.itemIndex ||
oldWidget.route.animation != widget.route.animation ||
oldWidget.route.selectedIndex != widget.route.selectedIndex ||
widget.route.items.length != oldWidget.route.items.length ||
widget.route.dropdownStyle.openInterval.end !=
oldWidget.route.dropdownStyle.openInterval.end) {
_opacityAnimation.dispose();
_setOpacityAnimation();
}
}

@override
void dispose() {
_opacityAnimation.dispose();
super.dispose();
}

void _setOpacityAnimation() {
final double menuCurveEnd = widget.route.dropdownStyle.openInterval.end;
final double unit = 0.5 / (widget.route.items.length + 1.5);
final double start =
clampDouble(menuCurveEnd + (widget.itemIndex + 1) * unit, 0.0, 1.0);
final double end = clampDouble(start + 1.5 * unit, 0.0, 1.0);
_opacityAnimation = CurvedAnimation(
parent: widget.route.animation!,
curve: Interval(start, end),
);
}

void _handleFocusChange(bool focused) {
final bool inTraditionalMode =
switch (FocusManager.instance.highlightMode) {
Expand Down Expand Up @@ -197,15 +237,7 @@ class _DropdownItemButtonState<T> extends State<_DropdownItemButton<T>> {

@override
Widget build(BuildContext context) {
final double menuCurveEnd = widget.route.dropdownStyle.openInterval.end;

final DropdownItem<T> dropdownItem = widget.route.items[widget.itemIndex];
final double unit = 0.5 / (widget.route.items.length + 1.5);
final double start =
clampDouble(menuCurveEnd + (widget.itemIndex + 1) * unit, 0.0, 1.0);
final double end = clampDouble(start + 1.5 * unit, 0.0, 1.0);
final CurvedAnimation opacity = CurvedAnimation(
parent: widget.route.animation!, curve: Interval(start, end));

Widget child = Container(
padding: (menuItemStyle.padding ?? _kMenuItemPadding)
Expand All @@ -230,7 +262,7 @@ class _DropdownItemButtonState<T> extends State<_DropdownItemButton<T>> {
: child,
);
}
child = FadeTransition(opacity: opacity, child: child);
child = FadeTransition(opacity: _opacityAnimation, child: child);
if (kIsWeb && dropdownItem.enabled) {
child = Shortcuts(
shortcuts: _webShortcuts,
Expand Down