diff --git a/packages/dropdown_button2/CHANGELOG.md b/packages/dropdown_button2/CHANGELOG.md index d60c8f4..5241488 100644 --- a/packages/dropdown_button2/CHANGELOG.md +++ b/packages/dropdown_button2/CHANGELOG.md @@ -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 diff --git a/packages/dropdown_button2/lib/src/dropdown_menu.dart b/packages/dropdown_button2/lib/src/dropdown_menu.dart index 15279a8..7349f4a 100644 --- a/packages/dropdown_button2/lib/src/dropdown_menu.dart +++ b/packages/dropdown_button2/lib/src/dropdown_menu.dart @@ -38,8 +38,8 @@ class _DropdownMenu extends StatefulWidget { } class _DropdownMenuState extends State<_DropdownMenu> { - late CurvedAnimation _fadeOpacity; - late CurvedAnimation _resize; + late final CurvedAnimation _fadeOpacity; + late final CurvedAnimation _resize; late List _children; late SearchMatchFn _searchMatchFn; diff --git a/packages/dropdown_button2/lib/src/dropdown_menu_item.dart b/packages/dropdown_button2/lib/src/dropdown_menu_item.dart index 227e7ce..8c93db3 100644 --- a/packages/dropdown_button2/lib/src/dropdown_menu_item.dart +++ b/packages/dropdown_button2/lib/src/dropdown_menu_item.dart @@ -147,6 +147,46 @@ class _DropdownItemButton extends StatefulWidget { } class _DropdownItemButtonState extends State<_DropdownItemButton> { + late CurvedAnimation _opacityAnimation; + + @override + void initState() { + super.initState(); + _setOpacityAnimation(); + } + + @override + void didUpdateWidget(_DropdownItemButton 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) { @@ -197,15 +237,7 @@ class _DropdownItemButtonState extends State<_DropdownItemButton> { @override Widget build(BuildContext context) { - final double menuCurveEnd = widget.route.dropdownStyle.openInterval.end; - final DropdownItem 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) @@ -230,7 +262,7 @@ class _DropdownItemButtonState extends State<_DropdownItemButton> { : child, ); } - child = FadeTransition(opacity: opacity, child: child); + child = FadeTransition(opacity: _opacityAnimation, child: child); if (kIsWeb && dropdownItem.enabled) { child = Shortcuts( shortcuts: _webShortcuts,