Skip to content

Commit c1b7740

Browse files
authored
Fix: Gap between prefix and suffix icon and input field in input deco… (#152069)
Adjust the gap between TextField prefix/suffix and its content. Results in a small visual change for TextFields that use prefix and/or suffix.
1 parent d7a5db2 commit c1b7740

File tree

4 files changed

+125
-84
lines changed

4 files changed

+125
-84
lines changed

packages/flutter/lib/src/material/dropdown_menu.dart

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ const double _kMinimumWidth = 112.0;
4747

4848
const double _kDefaultHorizontalPadding = 12.0;
4949

50+
const double _kLeadingIconToInputPadding = 4.0;
51+
5052
/// Defines a [DropdownMenu] menu button that represents one item view in the menu.
5153
///
5254
/// See also:
@@ -610,7 +612,12 @@ class _DropdownMenuState<T> extends State<DropdownMenu<T>> {
610612
return;
611613
}
612614
setState(() {
613-
leadingPadding = getWidth(_leadingKey);
615+
final double? leadingWidgetWidth = getWidth(_leadingKey);
616+
if (leadingWidgetWidth != null) {
617+
leadingPadding = leadingWidgetWidth + _kLeadingIconToInputPadding;
618+
} else {
619+
leadingPadding = leadingWidgetWidth;
620+
}
614621
});
615622
}, debugLabel: 'DropdownMenu.refreshLeadingPadding');
616623
}
@@ -686,7 +693,7 @@ class _DropdownMenuState<T> extends State<DropdownMenu<T>> {
686693
// menu entry have leading icons, the menu entry should remove the extra
687694
// paddings so its leading icon will be aligned with the leading icon of
688695
// the text field.
689-
final double padding = entry.leadingIcon == null ? (leadingPadding ?? _kDefaultHorizontalPadding) : _kDefaultHorizontalPadding;
696+
final double padding = entry.leadingIcon == null ? (leadingPadding ?? _kDefaultHorizontalPadding) : (_kDefaultHorizontalPadding + _kLeadingIconToInputPadding);
690697
ButtonStyle effectiveStyle = entry.style ?? switch (textDirection) {
691698
TextDirection.rtl => MenuItemButton.styleFrom(padding: EdgeInsets.only(left: _kDefaultHorizontalPadding, right: padding)),
692699
TextDirection.ltr => MenuItemButton.styleFrom(padding: EdgeInsets.only(left: padding, right: _kDefaultHorizontalPadding)),

packages/flutter/lib/src/material/input_decorator.dart

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -740,6 +740,8 @@ class _RenderDecoration extends RenderBox with SlottedContainerRenderObjectMixin
740740
// TODO(bleroux): consider defining this value as a Material token and making it
741741
// configurable by InputDecorationTheme.
742742
double get subtextGap => material3 ? 4.0 : 8.0;
743+
double get prefixToInputGap => material3 ? 4.0 : 0.0;
744+
double get inputToSuffixGap => material3 ? 4.0 : 0.0;
743745

744746
RenderBox? get icon => childForSlot(_DecorationSlot.icon);
745747
RenderBox? get input => childForSlot(_DecorationSlot.input);
@@ -997,8 +999,8 @@ class _RenderDecoration extends RenderBox with SlottedContainerRenderObjectMixin
997999
final Size suffixSize = suffix == null ? Size.zero : layoutChild(suffix, contentConstraints);
9981000

9991001
final EdgeInsetsDirectional accessoryHorizontalInsets = EdgeInsetsDirectional.only(
1000-
start: iconWidth + prefixSize.width + (prefixIcon == null ? contentPadding.start : prefixIconSize.width),
1001-
end: suffixSize.width + (suffixIcon == null ? contentPadding.end : suffixIconSize.width),
1002+
start: iconWidth + prefixSize.width + (prefixIcon == null ? contentPadding.start : prefixIconSize.width + prefixToInputGap),
1003+
end: suffixSize.width + (suffixIcon == null ? contentPadding.end : suffixIconSize.width + inputToSuffixGap),
10021004
);
10031005

10041006
final double inputWidth = math.max(0.0, constraints.maxWidth - accessoryHorizontalInsets.horizontal);
@@ -1165,25 +1167,25 @@ class _RenderDecoration extends RenderBox with SlottedContainerRenderObjectMixin
11651167
@override
11661168
double computeMinIntrinsicWidth(double height) {
11671169
return _minWidth(icon, height)
1168-
+ (prefixIcon != null ? 0.0 : contentPadding.start)
1170+
+ (prefixIcon != null ? prefixToInputGap : contentPadding.start)
11691171
+ _minWidth(prefixIcon, height)
11701172
+ _minWidth(prefix, height)
11711173
+ math.max(_minWidth(input, height), _minWidth(hint, height))
11721174
+ _minWidth(suffix, height)
11731175
+ _minWidth(suffixIcon, height)
1174-
+ (suffixIcon != null ? 0.0 : contentPadding.end);
1176+
+ (suffixIcon != null ? inputToSuffixGap : contentPadding.end);
11751177
}
11761178

11771179
@override
11781180
double computeMaxIntrinsicWidth(double height) {
11791181
return _maxWidth(icon, height)
1180-
+ (prefixIcon != null ? 0.0 : contentPadding.start)
1182+
+ (prefixIcon != null ? prefixToInputGap : contentPadding.start)
11811183
+ _maxWidth(prefixIcon, height)
11821184
+ _maxWidth(prefix, height)
11831185
+ math.max(_maxWidth(input, height), _maxWidth(hint, height))
11841186
+ _maxWidth(suffix, height)
11851187
+ _maxWidth(suffixIcon, height)
1186-
+ (suffixIcon != null ? 0.0 : contentPadding.end);
1188+
+ (suffixIcon != null ? inputToSuffixGap : contentPadding.end);
11871189
}
11881190

11891191
double _lineHeight(double width, List<RenderBox?> boxes) {
@@ -1371,6 +1373,7 @@ class _RenderDecoration extends RenderBox with SlottedContainerRenderObjectMixin
13711373
if (prefixIcon != null) {
13721374
start += contentPadding.start;
13731375
start -= centerLayout(prefixIcon!, start - prefixIcon!.size.width);
1376+
start -= prefixToInputGap;
13741377
}
13751378
if (label != null) {
13761379
if (decoration.alignLabelWithHint) {
@@ -1391,6 +1394,7 @@ class _RenderDecoration extends RenderBox with SlottedContainerRenderObjectMixin
13911394
if (suffixIcon != null) {
13921395
end -= contentPadding.end;
13931396
end += centerLayout(suffixIcon!, end);
1397+
end += inputToSuffixGap;
13941398
}
13951399
if (suffix != null) {
13961400
end += baselineLayout(suffix!, end);
@@ -1401,6 +1405,7 @@ class _RenderDecoration extends RenderBox with SlottedContainerRenderObjectMixin
14011405
if (prefixIcon != null) {
14021406
start -= contentPadding.start;
14031407
start += centerLayout(prefixIcon!, start);
1408+
start += prefixToInputGap;
14041409
}
14051410
if (label != null) {
14061411
if (decoration.alignLabelWithHint) {
@@ -1421,6 +1426,7 @@ class _RenderDecoration extends RenderBox with SlottedContainerRenderObjectMixin
14211426
if (suffixIcon != null) {
14221427
end += contentPadding.end;
14231428
end -= centerLayout(suffixIcon!, end - suffixIcon!.size.width);
1429+
end -= inputToSuffixGap;
14241430
}
14251431
if (suffix != null) {
14261432
end -= baselineLayout(suffix!, end - suffix!.size.width);

packages/flutter/test/material/dropdown_menu_test.dart

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ void main() {
1414
const String longText = 'one two three four five six seven eight nine ten eleven twelve';
1515
final List<DropdownMenuEntry<TestMenu>> menuChildren = <DropdownMenuEntry<TestMenu>>[];
1616
final List<DropdownMenuEntry<TestMenu>> menuChildrenWithIcons = <DropdownMenuEntry<TestMenu>>[];
17+
const double leadingIconToInputPadding = 4.0;
1718

1819
for (final TestMenu value in TestMenu.values) {
1920
final DropdownMenuEntry<TestMenu> entry = DropdownMenuEntry<TestMenu>(value: value, label: value.label);
@@ -921,7 +922,7 @@ void main() {
921922
final Offset updatedItemTextTopLeft = tester.getTopLeft(updatedItemText);
922923

923924
expect(updatedLabelTopLeft.dx, equals(updatedItemTextTopLeft.dx));
924-
expect(updatedLabelTopLeft.dx, equals(iconWidth));
925+
expect(updatedLabelTopLeft.dx, equals(iconWidth + leadingIconToInputPadding));
925926

926927
// Test when then leading icon is a widget with a bigger size.
927928
await tester.pumpWidget(Container());
@@ -943,7 +944,7 @@ void main() {
943944
final Offset updatedItemTextTopLeft1 = tester.getTopLeft(updatedItemText1);
944945

945946
expect(updatedLabelTopLeft1.dx, equals(updatedItemTextTopLeft1.dx));
946-
expect(updatedLabelTopLeft1.dx, equals(largeIconWidth));
947+
expect(updatedLabelTopLeft1.dx, equals(largeIconWidth + leadingIconToInputPadding));
947948
});
948949

949950
testWidgets('The text in the menu button should be aligned with the text of '
@@ -1002,7 +1003,7 @@ void main() {
10021003
final Offset updatedItemTextTopRight = tester.getTopRight(updatedItemText);
10031004

10041005
expect(updatedLabelTopRight.dx, equals(updatedItemTextTopRight.dx));
1005-
expect(updatedLabelTopRight.dx, equals(dropdownMenuTopRight.dx - iconWidth));
1006+
expect(updatedLabelTopRight.dx, equals(dropdownMenuTopRight.dx - iconWidth - leadingIconToInputPadding));
10061007

10071008
// Test when then leading icon is a widget with a bigger size.
10081009
await tester.pumpWidget(Container());
@@ -1033,7 +1034,7 @@ void main() {
10331034
final Offset updatedItemTextTopRight1 = tester.getTopRight(updatedItemText1);
10341035

10351036
expect(updatedLabelTopRight1.dx, equals(updatedItemTextTopRight1.dx));
1036-
expect(updatedLabelTopRight1.dx, equals(updatedDropdownMenuTopRight.dx - largeIconWidth));
1037+
expect(updatedLabelTopRight1.dx, equals(updatedDropdownMenuTopRight.dx - largeIconWidth - leadingIconToInputPadding));
10371038
});
10381039

10391040
testWidgets('DropdownMenu has default trailing icon button', (WidgetTester tester) async {
@@ -2712,14 +2713,14 @@ void main() {
27122713
await tester.pumpAndSettle();
27132714

27142715
// Check text location in text field.
2715-
expect(tester.getTopLeft(find.text('Hint')).dx, 48.0);
2716+
expect(tester.getTopLeft(find.text('Hint')).dx, 52.0);
27162717

27172718
// By default, the text of item 0 should be aligned with the text of the text field.
2718-
expect(tester.getTopLeft(find.text('Item 0').last).dx, 48.0);
2719+
expect(tester.getTopLeft(find.text('Item 0').last).dx, 52.0);
27192720

27202721
// By default, the text of item 1 should be aligned with the text of the text field,
27212722
// so there are some extra padding before "Item 1".
2722-
expect(tester.getTopLeft(find.text('Item 1').last).dx, 48.0);
2723+
expect(tester.getTopLeft(find.text('Item 1').last).dx, 52.0);
27232724
});
27242725

27252726
testWidgets('DropdownMenu can have customized search algorithm', (WidgetTester tester) async {

0 commit comments

Comments
 (0)