Skip to content

Avoid Container objects when possible for better performance [Flutter… #351

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 @@ -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

Expand Down
76 changes: 39 additions & 37 deletions packages/dropdown_button2/lib/src/dropdown_button2.dart
Original file line number Diff line number Diff line change
Expand Up @@ -785,7 +785,7 @@ class _DropdownButton2State<T> extends State<DropdownButton2<T>>
? _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],
Expand All @@ -794,45 +794,47 @@ class _DropdownButton2State<T> extends State<DropdownButton2<T>>
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: <Widget>[
if (widget.isExpanded)
Expanded(child: innerItemsWidget)
else
innerItemsWidget,
IconTheme(
data: IconThemeData(
color: _iconColor,
size: _iconStyle.iconSize,
),
child: ValueListenableBuilder<bool>(
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: <Widget>[
if (widget.isExpanded)
Expanded(child: innerItemsWidget)
else
innerItemsWidget,
IconTheme(
data: IconThemeData(
color: _iconColor,
size: _iconStyle.iconSize,
),
child: ValueListenableBuilder<bool>(
valueListenable: _isMenuOpen,
builder: (BuildContext context, bool isOpen, _) {
return _iconStyle.openMenuIcon != null
? isOpen
? _iconStyle.openMenuIcon!
: _iconStyle.icon
: _iconStyle.icon;
},
),
),
),
],
],
),
),
),
);
Expand Down
7 changes: 3 additions & 4 deletions packages/dropdown_button2/lib/src/dropdown_menu_item.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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),
);
}
}
Expand Down Expand Up @@ -239,7 +238,7 @@ class _DropdownItemButtonState<T> extends State<_DropdownItemButton<T>> {
Widget build(BuildContext context) {
final DropdownItem<T> dropdownItem = widget.route.items[widget.itemIndex];

Widget child = Container(
Widget child = Padding(
padding: (menuItemStyle.padding ?? _kMenuItemPadding)
.resolve(widget.textDirection),
child: dropdownItem,
Expand Down
29 changes: 29 additions & 0 deletions packages/dropdown_button2/lib/src/utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,35 @@ void _uniqueValueAssert<T>(
);
}

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,
Expand Down