diff --git a/README.md b/README.md index 1cc414c..a4c99f2 100644 --- a/README.md +++ b/README.md @@ -136,12 +136,13 @@ customize to your needs. #### Subclass MenuItemStyleData: -| Option | Description | Type | Required | -| ------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------- | ----------------------------- | :------: | -| [padding](https://pub.dev/documentation/dropdown_button2/latest/dropdown_button2/MenuItemStyleData/padding.html) | The padding of menu items | EdgeInsetsGeometry | No | -| [borderRadius](https://pub.dev/documentation/dropdown_button2/latest/dropdown_button2/MenuItemStyleData/borderRadius.html) | The border radius of the menu item | BorderRadius | No | -| [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 | No | -| [selectedMenuItemBuilder](https://pub.dev/documentation/dropdown_button2/latest/dropdown_button2/MenuItemStyleData/selectedMenuItemBuilder.html) | A builder to customize the selected menu item | SelectedMenuItemBuilder | No | +| Option | Description | Type | Required | +| -------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------- | :------: | +| [padding](https://pub.dev/documentation/dropdown_button2/latest/dropdown_button2/MenuItemStyleData/padding.html) | The padding of menu items | EdgeInsetsGeometry | No | +| [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 | +| [borderRadius](https://pub.dev/documentation/dropdown_button2/latest/dropdown_button2/MenuItemStyleData/borderRadius.html) | The border radius of the menu item | BorderRadius | No | +| [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 | No | +| [selectedMenuItemBuilder](https://pub.dev/documentation/dropdown_button2/latest/dropdown_button2/MenuItemStyleData/selectedMenuItemBuilder.html) | A builder to customize the selected menu item | SelectedMenuItemBuilder | No | #### Subclass DropdownSearchData: @@ -954,9 +955,8 @@ Widget build(BuildContext context) { DropdownButtonFormField2( isExpanded: true, decoration: InputDecoration( - // Add Horizontal padding using menuItemStyleData.padding so it matches - // the menu padding when button's width is not specified. - contentPadding: const EdgeInsets.symmetric(vertical: 16), + contentPadding: + const EdgeInsets.symmetric(vertical: 16, horizontal: 16), border: OutlineInputBorder( borderRadius: BorderRadius.circular(15), ), @@ -999,7 +999,7 @@ Widget build(BuildContext context) { ), ), menuItemStyleData: const MenuItemStyleData( - padding: EdgeInsets.symmetric(horizontal: 16), + useDecorationHorizontalPadding: true, ), ), const SizedBox(height: 30), diff --git a/packages/dropdown_button2/CHANGELOG.md b/packages/dropdown_button2/CHANGELOG.md index bab3cdb..89f96fc 100644 --- a/packages/dropdown_button2/CHANGELOG.md +++ b/packages/dropdown_button2/CHANGELOG.md @@ -9,6 +9,7 @@ - Avoid Container objects when possible for better performance [Flutter core]. - Add semantics to dropdown menu items [Flutter core]. - Support helperStyle/helperMaxLines/errorMaxLines for DropdownButtonFormField2. +- Add `MenuItemStyleData.useDecorationHorizontalPadding`, used to determine whether to use the horizontal padding from "decoration.contentPadding" for menu items when using `DropdownButtonFormField2`. ## 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 224d45a..e094836 100644 --- a/packages/dropdown_button2/lib/src/dropdown_button2.dart +++ b/packages/dropdown_button2/lib/src/dropdown_button2.dart @@ -555,13 +555,10 @@ class _DropdownButton2State extends State> widget.style ?? Theme.of(context).textTheme.titleMedium; Rect _getButtonRect() { - final TextDirection? textDirection = Directionality.maybeOf(context); - final EdgeInsetsGeometry contentPadding = switch (widget._inputDecoration) { - final decoration? => decoration.contentPadding ?? - Theme.of(context).inputDecorationTheme.contentPadding ?? - EdgeInsets.zero, - null => EdgeInsets.zero, - }; + // InputDecorator is a parent of _buttonRect (to avoid the dropdown menu opening under the button's error/helper), + // so we need to consider its padding in additional to _buttonRect. + final EdgeInsets contentPadding = + _getInputDecorationPadding() ?? EdgeInsets.zero; final NavigatorState navigator = Navigator.of(context, rootNavigator: _dropdownStyle.isFullScreen ?? _dropdownStyle.useRootNavigator); @@ -572,13 +569,38 @@ class _DropdownButton2State extends State> ancestor: navigator.context.findRenderObject()) & itemBox.size; - return contentPadding.resolve(textDirection).inflateRect(itemRect); + return contentPadding.inflateRect(itemRect); + } + + EdgeInsets? _getInputDecorationPadding() { + // Return the contentPadding only if inputDecoration is defined. + if (widget._inputDecoration case final decoration?) { + final TextDirection? textDirection = Directionality.maybeOf(context); + return (decoration.contentPadding ?? + Theme.of(context).inputDecorationTheme.contentPadding) + ?.resolve(textDirection); + } else { + return null; + } } - EdgeInsetsGeometry _getMenuPadding() { - return (_menuItemStyle.padding ?? _kMenuItemPadding) + EdgeInsetsGeometry _buttonAdditionalHPadding() { + final TextDirection? textDirection = Directionality.maybeOf(context); + + final menuItemPadding = + _menuItemStyle.padding?.resolve(textDirection) ?? _kMenuItemPadding; + final removeItemHPadding = _menuItemStyle.useDecorationHorizontalPadding && + _getInputDecorationPadding() != null; + final effectiveMenuItemPadding = menuItemPadding.copyWith( + left: removeItemHPadding ? 0 : null, + right: removeItemHPadding ? 0 : null, + ); + + return effectiveMenuItemPadding .add(_dropdownStyle.padding ?? EdgeInsets.zero) - .add(_dropdownStyle.scrollPadding ?? EdgeInsets.zero); + .add(_dropdownStyle.scrollPadding ?? EdgeInsets.zero) + .resolve(textDirection) + .copyWith(top: 0, bottom: 0); } void _handleTap() { @@ -609,6 +631,7 @@ class _DropdownButton2State extends State> enableFeedback: widget.enableFeedback ?? true, dropdownStyle: _dropdownStyle, menuItemStyle: _menuItemStyle, + inputDecorationPadding: _getInputDecorationPadding(), searchData: _searchData, dropdownSeparator: separator, ); @@ -684,7 +707,7 @@ class _DropdownButton2State extends State> final buttonRadius = _buttonStyle?.decoration?.borderRadius ?? _buttonStyle?.foregroundDecoration?.borderRadius; if (buttonRadius != null) { - return buttonRadius.resolve(Directionality.of(context)); + return buttonRadius.resolve(Directionality.maybeOf(context)); } return null; } @@ -789,16 +812,12 @@ class _DropdownButton2State extends State> height: buttonHeight, width: _buttonStyle?.width, child: Padding( - padding: (_buttonStyle?.padding ?? - padding.resolve(Directionality.of(context))) - .add( + padding: (_buttonStyle?.padding ?? padding).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 + // We need to add menu's horizontal padding 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) + ? _buttonAdditionalHPadding() : EdgeInsets.zero, ), child: Row( diff --git a/packages/dropdown_button2/lib/src/dropdown_menu.dart b/packages/dropdown_button2/lib/src/dropdown_menu.dart index 7349f4a..12e3441 100644 --- a/packages/dropdown_button2/lib/src/dropdown_menu.dart +++ b/packages/dropdown_button2/lib/src/dropdown_menu.dart @@ -268,9 +268,8 @@ class _DropdownMenuState extends State<_DropdownMenu> { clipBehavior: dropdownStyle.decoration?.borderRadius != null ? Clip.antiAlias : Clip.none, - borderRadius: dropdownStyle.decoration?.borderRadius - ?.resolve(Directionality.of(context)) ?? - BorderRadius.zero, + borderRadius: + dropdownStyle.decoration?.borderRadius ?? BorderRadius.zero, child: dropdownStyle.dropdownBuilder?.call(context, dropdownMenu) ?? dropdownMenu, ), diff --git a/packages/dropdown_button2/lib/src/dropdown_menu_item.dart b/packages/dropdown_button2/lib/src/dropdown_menu_item.dart index 83fb071..589cbc0 100644 --- a/packages/dropdown_button2/lib/src/dropdown_menu_item.dart +++ b/packages/dropdown_button2/lib/src/dropdown_menu_item.dart @@ -235,15 +235,25 @@ class _DropdownItemButtonState extends State<_DropdownItemButton> { DirectionalFocusIntent(TraversalDirection.up), }; - MenuItemStyleData get menuItemStyle => widget.route.menuItemStyle; + MenuItemStyleData get _menuItemStyle => widget.route.menuItemStyle; + EdgeInsets? get _inputDecorationPadding => + widget.route.inputDecorationPadding; + bool get _useDecorationHPadding => + _menuItemStyle.useDecorationHorizontalPadding; @override Widget build(BuildContext context) { final DropdownItem dropdownItem = widget.route.items[widget.itemIndex]; + final menuItemPadding = + _menuItemStyle.padding?.resolve(widget.textDirection) ?? + _kMenuItemPadding; + Widget child = Padding( - padding: (menuItemStyle.padding ?? _kMenuItemPadding) - .resolve(widget.textDirection), + padding: menuItemPadding.copyWith( + left: _useDecorationHPadding ? _inputDecorationPadding?.left : null, + right: _useDecorationHPadding ? _inputDecorationPadding?.right : null, + ), child: dropdownItem, ); // An [InkWell] is added to the item only if it is enabled @@ -256,10 +266,10 @@ class _DropdownItemButtonState extends State<_DropdownItemButton> { enableFeedback: widget.enableFeedback, onTap: _handleOnTap, onFocusChange: _handleFocusChange, - borderRadius: menuItemStyle.borderRadius, - overlayColor: menuItemStyle.overlayColor, + borderRadius: _menuItemStyle.borderRadius, + overlayColor: _menuItemStyle.overlayColor, child: isSelectedItem - ? menuItemStyle.selectedMenuItemBuilder?.call(context, child) ?? + ? _menuItemStyle.selectedMenuItemBuilder?.call(context, child) ?? child : child, ); diff --git a/packages/dropdown_button2/lib/src/dropdown_route.dart b/packages/dropdown_button2/lib/src/dropdown_route.dart index d699aca..53f8cb1 100644 --- a/packages/dropdown_button2/lib/src/dropdown_route.dart +++ b/packages/dropdown_button2/lib/src/dropdown_route.dart @@ -17,6 +17,7 @@ class _DropdownRoute extends PopupRoute<_DropdownRouteResult> { required this.enableFeedback, required this.dropdownStyle, required this.menuItemStyle, + required this.inputDecorationPadding, required this.searchData, this.dropdownSeparator, }) : barrierColor = barrierCoversButton ? barrierColor : null, @@ -33,6 +34,7 @@ class _DropdownRoute extends PopupRoute<_DropdownRouteResult> { final bool enableFeedback; final DropdownStyleData dropdownStyle; final MenuItemStyleData menuItemStyle; + final EdgeInsets? inputDecorationPadding; final DropdownSearchData? searchData; final DropdownSeparator? dropdownSeparator; diff --git a/packages/dropdown_button2/lib/src/dropdown_style_data.dart b/packages/dropdown_button2/lib/src/dropdown_style_data.dart index 733e0e0..6be70a6 100644 --- a/packages/dropdown_button2/lib/src/dropdown_style_data.dart +++ b/packages/dropdown_button2/lib/src/dropdown_style_data.dart @@ -153,6 +153,7 @@ class MenuItemStyleData { /// Creates a MenuItemStyleData. const MenuItemStyleData({ this.padding, + this.useDecorationHorizontalPadding = false, this.borderRadius, this.overlayColor, this.selectedMenuItemBuilder, @@ -164,6 +165,13 @@ class MenuItemStyleData { /// the menu width and button width adapt seamlessly to the maximum width of the items. final EdgeInsetsGeometry? padding; + /// Whether to use the horizontal padding from `decoration.contentPadding` + /// instead of `padding`, applicable only when using `DropdownButtonFormField2`. + /// + /// If `true`, the horizontal padding defined in `decoration.contentPadding` + /// will be applied, ensuring consistency with the form field's padding. + final bool useDecorationHorizontalPadding; + /// The border radius of the menu item. final BorderRadius? borderRadius; diff --git a/packages/dropdown_button2_test/lib/src/form_field_example.dart b/packages/dropdown_button2_test/lib/src/form_field_example.dart index 0c4e2c2..32ad21c 100644 --- a/packages/dropdown_button2_test/lib/src/form_field_example.dart +++ b/packages/dropdown_button2_test/lib/src/form_field_example.dart @@ -41,9 +41,8 @@ class _FormFieldExampleState extends State { DropdownButtonFormField2( isExpanded: true, decoration: InputDecoration( - // Add Horizontal padding using menuItemStyleData.padding so it matches - // the menu padding when button's width is not specified. - contentPadding: const EdgeInsets.symmetric(vertical: 16), + contentPadding: + const EdgeInsets.symmetric(vertical: 16, horizontal: 16), border: OutlineInputBorder( borderRadius: BorderRadius.circular(15), ), @@ -86,7 +85,7 @@ class _FormFieldExampleState extends State { ), ), menuItemStyleData: const MenuItemStyleData( - padding: EdgeInsets.symmetric(horizontal: 16), + useDecorationHorizontalPadding: true, ), ), const SizedBox(height: 30),