From 10e745d19d843b46f2138b4a9a1664e4bd5e7df3 Mon Sep 17 00:00:00 2001 From: Ahmed Elsayed Date: Fri, 7 Mar 2025 19:46:51 +0200 Subject: [PATCH] Avoid Container objects when possible for better performance [Flutter core] --- packages/dropdown_button2/CHANGELOG.md | 1 + .../lib/src/dropdown_button2.dart | 76 ++++++++++--------- .../lib/src/dropdown_menu_item.dart | 7 +- packages/dropdown_button2/lib/src/utils.dart | 29 +++++++ 4 files changed, 72 insertions(+), 41 deletions(-) diff --git a/packages/dropdown_button2/CHANGELOG.md b/packages/dropdown_button2/CHANGELOG.md index 5241488..69dfe9d 100644 --- a/packages/dropdown_button2/CHANGELOG.md +++ b/packages/dropdown_button2/CHANGELOG.md @@ -6,6 +6,7 @@ - Form fields onChange callback should be called on reset [Flutter core]. - Implement switch expressions. - Fix memory leak in CurvedAnimation [Flutter core]. +- Avoid Container objects when possible for better performance [Flutter core]. ## 3.0.0-beta.21 diff --git a/packages/dropdown_button2/lib/src/dropdown_button2.dart b/packages/dropdown_button2/lib/src/dropdown_button2.dart index 64ffb28..4667c79 100644 --- a/packages/dropdown_button2/lib/src/dropdown_button2.dart +++ b/packages/dropdown_button2/lib/src/dropdown_button2.dart @@ -785,7 +785,7 @@ class _DropdownButton2State extends State> ? _textStyle! : _textStyle!.copyWith(color: Theme.of(context).disabledColor), child: widget.customButton ?? - Container( + _ConditionalDecoratedBox( decoration: _buttonStyle?.decoration?.copyWith( boxShadow: _buttonStyle!.decoration!.boxShadow ?? kElevationToShadow[_buttonStyle!.elevation ?? 0], @@ -794,45 +794,47 @@ class _DropdownButton2State extends State> boxShadow: _buttonStyle!.foregroundDecoration!.boxShadow ?? kElevationToShadow[_buttonStyle!.elevation ?? 0], ), - padding: (_buttonStyle?.padding ?? - padding.resolve(Directionality.of(context))) - .add( - // When buttonWidth & dropdownWidth is null, their width will be calculated - // from the maximum width of menu items or the hint text (width of IndexedStack). - // We need to add MenuHorizontalPadding so menu width adapts to max items width with padding properly - _buttonStyle?.width == null && _dropdownStyle.width == null - ? _getMenuPadding() - .resolve(Directionality.of(context)) - .copyWith(top: 0, bottom: 0) - : EdgeInsets.zero, - ), height: buttonHeight, width: _buttonStyle?.width, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - mainAxisSize: MainAxisSize.min, - children: [ - if (widget.isExpanded) - Expanded(child: innerItemsWidget) - else - innerItemsWidget, - IconTheme( - data: IconThemeData( - color: _iconColor, - size: _iconStyle.iconSize, - ), - child: ValueListenableBuilder( - valueListenable: _isMenuOpen, - builder: (BuildContext context, bool isOpen, _) { - return _iconStyle.openMenuIcon != null - ? isOpen - ? _iconStyle.openMenuIcon! - : _iconStyle.icon - : _iconStyle.icon; - }, + child: Padding( + padding: (_buttonStyle?.padding ?? + padding.resolve(Directionality.of(context))) + .add( + // When buttonWidth & dropdownWidth is null, their width will be calculated + // from the maximum width of menu items or the hint text (width of IndexedStack). + // We need to add MenuHorizontalPadding so menu width adapts to max items width with padding properly + _buttonStyle?.width == null && _dropdownStyle.width == null + ? _getMenuPadding() + .resolve(Directionality.of(context)) + .copyWith(top: 0, bottom: 0) + : EdgeInsets.zero, + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + mainAxisSize: MainAxisSize.min, + children: [ + if (widget.isExpanded) + Expanded(child: innerItemsWidget) + else + innerItemsWidget, + IconTheme( + data: IconThemeData( + color: _iconColor, + size: _iconStyle.iconSize, + ), + child: ValueListenableBuilder( + valueListenable: _isMenuOpen, + builder: (BuildContext context, bool isOpen, _) { + return _iconStyle.openMenuIcon != null + ? isOpen + ? _iconStyle.openMenuIcon! + : _iconStyle.icon + : _iconStyle.icon; + }, + ), ), - ), - ], + ], + ), ), ), ); diff --git a/packages/dropdown_button2/lib/src/dropdown_menu_item.dart b/packages/dropdown_button2/lib/src/dropdown_menu_item.dart index 8c93db3..1ed6ee5 100644 --- a/packages/dropdown_button2/lib/src/dropdown_menu_item.dart +++ b/packages/dropdown_button2/lib/src/dropdown_menu_item.dart @@ -111,10 +111,9 @@ class _DropdownMenuItemContainer extends StatelessWidget { @override Widget build(BuildContext context) { - return Container( + return SizedBox( height: intrinsicHeight ? null : height, - alignment: alignment, - child: child, + child: Align(alignment: alignment, child: child), ); } } @@ -239,7 +238,7 @@ class _DropdownItemButtonState extends State<_DropdownItemButton> { Widget build(BuildContext context) { final DropdownItem dropdownItem = widget.route.items[widget.itemIndex]; - Widget child = Container( + Widget child = Padding( padding: (menuItemStyle.padding ?? _kMenuItemPadding) .resolve(widget.textDirection), child: dropdownItem, diff --git a/packages/dropdown_button2/lib/src/utils.dart b/packages/dropdown_button2/lib/src/utils.dart index ada306e..5815180 100644 --- a/packages/dropdown_button2/lib/src/utils.dart +++ b/packages/dropdown_button2/lib/src/utils.dart @@ -36,6 +36,35 @@ void _uniqueValueAssert( ); } +class _ConditionalDecoratedBox extends StatelessWidget { + const _ConditionalDecoratedBox({ + required this.child, + this.height, + this.width, + this.decoration, + this.foregroundDecoration, + }); + + final double? height; + final double? width; + final Decoration? decoration; + final Decoration? foregroundDecoration; + final Widget child; + + @override + Widget build(BuildContext context) { + return decoration != null || foregroundDecoration != null + ? Container( + height: height, + width: width, + decoration: decoration, + foregroundDecoration: foregroundDecoration, + child: child, + ) + : SizedBox(height: height, width: width, child: child); + } +} + extension _InputDecorationExtension on InputDecoration { InputDecoration updateSurroundingElements({ required Widget? error,