Skip to content

Commit 7c2fb6b

Browse files
authored
Merge pull request #356 from AhmedLSayed9/support_using_input_decoration_content_padding
Support using inputDecoration’s horizontal padding for button and menu items
2 parents 2e3af4d + e2d10e9 commit 7c2fb6b

File tree

8 files changed

+80
-42
lines changed

8 files changed

+80
-42
lines changed

README.md

+10-10
Original file line numberDiff line numberDiff line change
@@ -136,12 +136,13 @@ customize to your needs.
136136

137137
#### Subclass MenuItemStyleData:
138138

139-
| Option | Description | Type | Required |
140-
| ------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------- | ----------------------------- | :------: |
141-
| [padding](https://pub.dev/documentation/dropdown_button2/latest/dropdown_button2/MenuItemStyleData/padding.html) | The padding of menu items | EdgeInsetsGeometry | No |
142-
| [borderRadius](https://pub.dev/documentation/dropdown_button2/latest/dropdown_button2/MenuItemStyleData/borderRadius.html) | The border radius of the menu item | BorderRadius | No |
143-
| [overlayColor](https://pub.dev/documentation/dropdown_button2/latest/dropdown_button2/MenuItemStyleData/overlayColor.html) | Defines the ink response focus, hover, and splash colors for the items | MaterialStateProperty<Color?> | No |
144-
| [selectedMenuItemBuilder](https://pub.dev/documentation/dropdown_button2/latest/dropdown_button2/MenuItemStyleData/selectedMenuItemBuilder.html) | A builder to customize the selected menu item | SelectedMenuItemBuilder | No |
139+
| Option | Description | Type | Required |
140+
| -------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------- | :------: |
141+
| [padding](https://pub.dev/documentation/dropdown_button2/latest/dropdown_button2/MenuItemStyleData/padding.html) | The padding of menu items | EdgeInsetsGeometry | No |
142+
| [useDecorationHorizontalPadding](https://pub.dev/documentation/dropdown_button2/latest/dropdown_button2/MenuItemStyleData/useDecorationHorizontalPadding.html) | Determine whether to use the horizontal padding from "decoration.contentPadding" for menu items when using `DropdownButtonFormField2` | bool | No |
143+
| [borderRadius](https://pub.dev/documentation/dropdown_button2/latest/dropdown_button2/MenuItemStyleData/borderRadius.html) | The border radius of the menu item | BorderRadius | No |
144+
| [overlayColor](https://pub.dev/documentation/dropdown_button2/latest/dropdown_button2/MenuItemStyleData/overlayColor.html) | Defines the ink response focus, hover, and splash colors for the items | MaterialStateProperty<Color?> | No |
145+
| [selectedMenuItemBuilder](https://pub.dev/documentation/dropdown_button2/latest/dropdown_button2/MenuItemStyleData/selectedMenuItemBuilder.html) | A builder to customize the selected menu item | SelectedMenuItemBuilder | No |
145146

146147
#### Subclass DropdownSearchData:
147148

@@ -954,9 +955,8 @@ Widget build(BuildContext context) {
954955
DropdownButtonFormField2<String>(
955956
isExpanded: true,
956957
decoration: InputDecoration(
957-
// Add Horizontal padding using menuItemStyleData.padding so it matches
958-
// the menu padding when button's width is not specified.
959-
contentPadding: const EdgeInsets.symmetric(vertical: 16),
958+
contentPadding:
959+
const EdgeInsets.symmetric(vertical: 16, horizontal: 16),
960960
border: OutlineInputBorder(
961961
borderRadius: BorderRadius.circular(15),
962962
),
@@ -999,7 +999,7 @@ Widget build(BuildContext context) {
999999
),
10001000
),
10011001
menuItemStyleData: const MenuItemStyleData(
1002-
padding: EdgeInsets.symmetric(horizontal: 16),
1002+
useDecorationHorizontalPadding: true,
10031003
),
10041004
),
10051005
const SizedBox(height: 30),

packages/dropdown_button2/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
- Avoid Container objects when possible for better performance [Flutter core].
1010
- Add semantics to dropdown menu items [Flutter core].
1111
- Support helperStyle/helperMaxLines/errorMaxLines for DropdownButtonFormField2.
12+
- Add `MenuItemStyleData.useDecorationHorizontalPadding`, used to determine whether to use the horizontal padding from "decoration.contentPadding" for menu items when using `DropdownButtonFormField2`.
1213

1314
## 3.0.0-beta.21
1415

packages/dropdown_button2/lib/src/dropdown_button2.dart

+38-19
Original file line numberDiff line numberDiff line change
@@ -555,13 +555,10 @@ class _DropdownButton2State<T> extends State<DropdownButton2<T>>
555555
widget.style ?? Theme.of(context).textTheme.titleMedium;
556556

557557
Rect _getButtonRect() {
558-
final TextDirection? textDirection = Directionality.maybeOf(context);
559-
final EdgeInsetsGeometry contentPadding = switch (widget._inputDecoration) {
560-
final decoration? => decoration.contentPadding ??
561-
Theme.of(context).inputDecorationTheme.contentPadding ??
562-
EdgeInsets.zero,
563-
null => EdgeInsets.zero,
564-
};
558+
// InputDecorator is a parent of _buttonRect (to avoid the dropdown menu opening under the button's error/helper),
559+
// so we need to consider its padding in additional to _buttonRect.
560+
final EdgeInsets contentPadding =
561+
_getInputDecorationPadding() ?? EdgeInsets.zero;
565562
final NavigatorState navigator = Navigator.of(context,
566563
rootNavigator:
567564
_dropdownStyle.isFullScreen ?? _dropdownStyle.useRootNavigator);
@@ -572,13 +569,38 @@ class _DropdownButton2State<T> extends State<DropdownButton2<T>>
572569
ancestor: navigator.context.findRenderObject()) &
573570
itemBox.size;
574571

575-
return contentPadding.resolve(textDirection).inflateRect(itemRect);
572+
return contentPadding.inflateRect(itemRect);
573+
}
574+
575+
EdgeInsets? _getInputDecorationPadding() {
576+
// Return the contentPadding only if inputDecoration is defined.
577+
if (widget._inputDecoration case final decoration?) {
578+
final TextDirection? textDirection = Directionality.maybeOf(context);
579+
return (decoration.contentPadding ??
580+
Theme.of(context).inputDecorationTheme.contentPadding)
581+
?.resolve(textDirection);
582+
} else {
583+
return null;
584+
}
576585
}
577586

578-
EdgeInsetsGeometry _getMenuPadding() {
579-
return (_menuItemStyle.padding ?? _kMenuItemPadding)
587+
EdgeInsetsGeometry _buttonAdditionalHPadding() {
588+
final TextDirection? textDirection = Directionality.maybeOf(context);
589+
590+
final menuItemPadding =
591+
_menuItemStyle.padding?.resolve(textDirection) ?? _kMenuItemPadding;
592+
final removeItemHPadding = _menuItemStyle.useDecorationHorizontalPadding &&
593+
_getInputDecorationPadding() != null;
594+
final effectiveMenuItemPadding = menuItemPadding.copyWith(
595+
left: removeItemHPadding ? 0 : null,
596+
right: removeItemHPadding ? 0 : null,
597+
);
598+
599+
return effectiveMenuItemPadding
580600
.add(_dropdownStyle.padding ?? EdgeInsets.zero)
581-
.add(_dropdownStyle.scrollPadding ?? EdgeInsets.zero);
601+
.add(_dropdownStyle.scrollPadding ?? EdgeInsets.zero)
602+
.resolve(textDirection)
603+
.copyWith(top: 0, bottom: 0);
582604
}
583605

584606
void _handleTap() {
@@ -609,6 +631,7 @@ class _DropdownButton2State<T> extends State<DropdownButton2<T>>
609631
enableFeedback: widget.enableFeedback ?? true,
610632
dropdownStyle: _dropdownStyle,
611633
menuItemStyle: _menuItemStyle,
634+
inputDecorationPadding: _getInputDecorationPadding(),
612635
searchData: _searchData,
613636
dropdownSeparator: separator,
614637
);
@@ -684,7 +707,7 @@ class _DropdownButton2State<T> extends State<DropdownButton2<T>>
684707
final buttonRadius = _buttonStyle?.decoration?.borderRadius ??
685708
_buttonStyle?.foregroundDecoration?.borderRadius;
686709
if (buttonRadius != null) {
687-
return buttonRadius.resolve(Directionality.of(context));
710+
return buttonRadius.resolve(Directionality.maybeOf(context));
688711
}
689712
return null;
690713
}
@@ -789,16 +812,12 @@ class _DropdownButton2State<T> extends State<DropdownButton2<T>>
789812
height: buttonHeight,
790813
width: _buttonStyle?.width,
791814
child: Padding(
792-
padding: (_buttonStyle?.padding ??
793-
padding.resolve(Directionality.of(context)))
794-
.add(
815+
padding: (_buttonStyle?.padding ?? padding).add(
795816
// When buttonWidth & dropdownWidth is null, their width will be calculated
796817
// from the maximum width of menu items or the hint text (width of IndexedStack).
797-
// We need to add MenuHorizontalPadding so menu width adapts to max items width with padding properly
818+
// We need to add menu's horizontal padding so menu width adapts to max items width with padding properly
798819
_buttonStyle?.width == null && _dropdownStyle.width == null
799-
? _getMenuPadding()
800-
.resolve(Directionality.of(context))
801-
.copyWith(top: 0, bottom: 0)
820+
? _buttonAdditionalHPadding()
802821
: EdgeInsets.zero,
803822
),
804823
child: Row(

packages/dropdown_button2/lib/src/dropdown_menu.dart

+2-3
Original file line numberDiff line numberDiff line change
@@ -268,9 +268,8 @@ class _DropdownMenuState<T> extends State<_DropdownMenu<T>> {
268268
clipBehavior: dropdownStyle.decoration?.borderRadius != null
269269
? Clip.antiAlias
270270
: Clip.none,
271-
borderRadius: dropdownStyle.decoration?.borderRadius
272-
?.resolve(Directionality.of(context)) ??
273-
BorderRadius.zero,
271+
borderRadius:
272+
dropdownStyle.decoration?.borderRadius ?? BorderRadius.zero,
274273
child: dropdownStyle.dropdownBuilder?.call(context, dropdownMenu) ??
275274
dropdownMenu,
276275
),

packages/dropdown_button2/lib/src/dropdown_menu_item.dart

+16-6
Original file line numberDiff line numberDiff line change
@@ -235,15 +235,25 @@ class _DropdownItemButtonState<T> extends State<_DropdownItemButton<T>> {
235235
DirectionalFocusIntent(TraversalDirection.up),
236236
};
237237

238-
MenuItemStyleData get menuItemStyle => widget.route.menuItemStyle;
238+
MenuItemStyleData get _menuItemStyle => widget.route.menuItemStyle;
239+
EdgeInsets? get _inputDecorationPadding =>
240+
widget.route.inputDecorationPadding;
241+
bool get _useDecorationHPadding =>
242+
_menuItemStyle.useDecorationHorizontalPadding;
239243

240244
@override
241245
Widget build(BuildContext context) {
242246
final DropdownItem<T> dropdownItem = widget.route.items[widget.itemIndex];
243247

248+
final menuItemPadding =
249+
_menuItemStyle.padding?.resolve(widget.textDirection) ??
250+
_kMenuItemPadding;
251+
244252
Widget child = Padding(
245-
padding: (menuItemStyle.padding ?? _kMenuItemPadding)
246-
.resolve(widget.textDirection),
253+
padding: menuItemPadding.copyWith(
254+
left: _useDecorationHPadding ? _inputDecorationPadding?.left : null,
255+
right: _useDecorationHPadding ? _inputDecorationPadding?.right : null,
256+
),
247257
child: dropdownItem,
248258
);
249259
// An [InkWell] is added to the item only if it is enabled
@@ -256,10 +266,10 @@ class _DropdownItemButtonState<T> extends State<_DropdownItemButton<T>> {
256266
enableFeedback: widget.enableFeedback,
257267
onTap: _handleOnTap,
258268
onFocusChange: _handleFocusChange,
259-
borderRadius: menuItemStyle.borderRadius,
260-
overlayColor: menuItemStyle.overlayColor,
269+
borderRadius: _menuItemStyle.borderRadius,
270+
overlayColor: _menuItemStyle.overlayColor,
261271
child: isSelectedItem
262-
? menuItemStyle.selectedMenuItemBuilder?.call(context, child) ??
272+
? _menuItemStyle.selectedMenuItemBuilder?.call(context, child) ??
263273
child
264274
: child,
265275
);

packages/dropdown_button2/lib/src/dropdown_route.dart

+2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ class _DropdownRoute<T> extends PopupRoute<_DropdownRouteResult<T>> {
1717
required this.enableFeedback,
1818
required this.dropdownStyle,
1919
required this.menuItemStyle,
20+
required this.inputDecorationPadding,
2021
required this.searchData,
2122
this.dropdownSeparator,
2223
}) : barrierColor = barrierCoversButton ? barrierColor : null,
@@ -33,6 +34,7 @@ class _DropdownRoute<T> extends PopupRoute<_DropdownRouteResult<T>> {
3334
final bool enableFeedback;
3435
final DropdownStyleData dropdownStyle;
3536
final MenuItemStyleData menuItemStyle;
37+
final EdgeInsets? inputDecorationPadding;
3638
final DropdownSearchData<T>? searchData;
3739
final DropdownSeparator<T>? dropdownSeparator;
3840

packages/dropdown_button2/lib/src/dropdown_style_data.dart

+8
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ class MenuItemStyleData {
153153
/// Creates a MenuItemStyleData.
154154
const MenuItemStyleData({
155155
this.padding,
156+
this.useDecorationHorizontalPadding = false,
156157
this.borderRadius,
157158
this.overlayColor,
158159
this.selectedMenuItemBuilder,
@@ -164,6 +165,13 @@ class MenuItemStyleData {
164165
/// the menu width and button width adapt seamlessly to the maximum width of the items.
165166
final EdgeInsetsGeometry? padding;
166167

168+
/// Whether to use the horizontal padding from `decoration.contentPadding`
169+
/// instead of `padding`, applicable only when using `DropdownButtonFormField2`.
170+
///
171+
/// If `true`, the horizontal padding defined in `decoration.contentPadding`
172+
/// will be applied, ensuring consistency with the form field's padding.
173+
final bool useDecorationHorizontalPadding;
174+
167175
/// The border radius of the menu item.
168176
final BorderRadius? borderRadius;
169177

packages/dropdown_button2_test/lib/src/form_field_example.dart

+3-4
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,8 @@ class _FormFieldExampleState extends State<FormFieldExample> {
4141
DropdownButtonFormField2<String>(
4242
isExpanded: true,
4343
decoration: InputDecoration(
44-
// Add Horizontal padding using menuItemStyleData.padding so it matches
45-
// the menu padding when button's width is not specified.
46-
contentPadding: const EdgeInsets.symmetric(vertical: 16),
44+
contentPadding:
45+
const EdgeInsets.symmetric(vertical: 16, horizontal: 16),
4746
border: OutlineInputBorder(
4847
borderRadius: BorderRadius.circular(15),
4948
),
@@ -86,7 +85,7 @@ class _FormFieldExampleState extends State<FormFieldExample> {
8685
),
8786
),
8887
menuItemStyleData: const MenuItemStyleData(
89-
padding: EdgeInsets.symmetric(horizontal: 16),
88+
useDecorationHorizontalPadding: true,
9089
),
9190
),
9291
const SizedBox(height: 30),

0 commit comments

Comments
 (0)