Skip to content

Commit ee3551f

Browse files
authored
Fix InputDecorator label padding (flutter#173344)
## Description This PR fixes the label padding for an InputDecorator with prefixIcon and/or suffixIcon. # Before The label was shorter than the available space because `InputDecoration.contentPadding.horizontal` was applied even when `prefixIcon` and `suffixIcon` were defined. The icons width replaces the corresponding `contentPadding`, so both should not be used at the same time to compute the available space. <img width="269" height="61" alt="image" src="https://github.com/user-attachments/assets/e1433ffb-8f17-46fe-9a65-6b9a504ef043" /> # After The label takes all the available space. <img width="269" height="61" alt="image" src="https://github.com/user-attachments/assets/12e8d087-c75b-48c9-8df4-1b11207c0e73" /> ## Related Issue Fixes [Label padding is wrong for InputDecorator with prefixIcon and/or suffixIcon ](flutter#173341) ## Tests Adds 1 test.
1 parent e2c7311 commit ee3551f

File tree

3 files changed

+85
-17
lines changed

3 files changed

+85
-17
lines changed

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1404,16 +1404,16 @@ class _RenderDropdownMenuBody extends RenderBox
14041404
child = childParentData.nextSibling;
14051405
continue;
14061406
}
1407-
final double maxIntrinsicWidth = child.getMinIntrinsicWidth(height);
1407+
final double minIntrinsicWidth = child.getMinIntrinsicWidth(height);
14081408
// Add the width of leading icon.
14091409
if (child == lastChild) {
1410-
width += maxIntrinsicWidth;
1410+
width += minIntrinsicWidth;
14111411
}
14121412
// Add the width of trailing icon.
14131413
if (child == childBefore(lastChild!)) {
1414-
width += maxIntrinsicWidth;
1414+
width += minIntrinsicWidth;
14151415
}
1416-
width = math.max(width, maxIntrinsicWidth);
1416+
width = math.max(width, minIntrinsicWidth);
14171417
final _DropdownMenuBodyParentData childParentData =
14181418
child.parentData! as _DropdownMenuBodyParentData;
14191419
child = childParentData.nextSibling;

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

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1012,16 +1012,15 @@ class _RenderDecoration extends RenderBox
10121012
final double topHeight;
10131013
if (label != null) {
10141014
final double suffixIconSpace = decoration.border.isOutline
1015-
? lerpDouble(suffixIconSize.width, 0.0, decoration.floatingLabelProgress)!
1015+
? lerpDouble(suffixIconSize.width, contentPadding.end, decoration.floatingLabelProgress)!
10161016
: suffixIconSize.width;
10171017
final double labelWidth = math.max(
10181018
0.0,
10191019
constraints.maxWidth -
10201020
(decoration.inputGap * 2 +
10211021
iconWidth +
1022-
contentPadding.horizontal +
1023-
prefixIconSize.width +
1024-
suffixIconSpace),
1022+
(prefixIcon == null ? contentPadding.start : prefixIconSize.width) +
1023+
(suffixIcon == null ? contentPadding.end : suffixIconSpace)),
10251024
);
10261025

10271026
// Increase the available width for the label when it is scaled down.

packages/flutter/test/material/input_decorator_test.dart

Lines changed: 78 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2951,6 +2951,71 @@ void main() {
29512951
// TODO(bleroux): fix input decorator to not rely on forcing the label text line height to 1.0.
29522952
});
29532953

2954+
testWidgets('When the label appears within the input its padding is correct', (
2955+
WidgetTester tester,
2956+
) async {
2957+
// Define a label larger than the available decorator, the label will fill
2958+
// all the available space (decorator width minus padding and affixes).
2959+
const Widget largeLabel = SizedBox(key: customLabelKey, width: 1000, height: 16);
2960+
await tester.pumpWidget(
2961+
buildInputDecorator(
2962+
isEmpty: true,
2963+
decoration: const InputDecoration(filled: true, label: largeLabel),
2964+
),
2965+
);
2966+
2967+
// For filled and/or outlined decoration, the horizontal padding is 16.
2968+
const double horizontalPadding = 16.0;
2969+
expect(getCustomLabelRect(tester).left, horizontalPadding);
2970+
expect(getCustomLabelRect(tester).right, 800 - horizontalPadding);
2971+
2972+
// Outlined decorator.
2973+
await tester.pumpWidget(
2974+
buildInputDecorator(
2975+
isEmpty: true,
2976+
decoration: const InputDecoration(border: OutlineInputBorder(), label: largeLabel),
2977+
),
2978+
);
2979+
2980+
expect(getCustomLabelRect(tester).left, horizontalPadding);
2981+
expect(getCustomLabelRect(tester).right, 800 - horizontalPadding);
2982+
2983+
// Rebuild with affixes.
2984+
await tester.pumpWidget(
2985+
buildInputDecorator(
2986+
isEmpty: true,
2987+
decoration: const InputDecoration(
2988+
filled: true,
2989+
label: largeLabel,
2990+
suffixIcon: Icon(Icons.align_horizontal_left_sharp),
2991+
prefixIcon: Icon(Icons.align_horizontal_right_sharp),
2992+
),
2993+
),
2994+
);
2995+
2996+
// When suffixIcon and/or prefixIcon are set, the corresponding horizontal
2997+
// padding is 52 (48 for the icon + 4 input gap based on M3 spec).
2998+
const double affixesHorizontalPadding = 52.0;
2999+
expect(getCustomLabelRect(tester).left, affixesHorizontalPadding);
3000+
expect(getCustomLabelRect(tester).right, 800 - affixesHorizontalPadding);
3001+
3002+
// Outlined decorator.
3003+
await tester.pumpWidget(
3004+
buildInputDecorator(
3005+
isEmpty: true,
3006+
decoration: const InputDecoration(
3007+
border: OutlineInputBorder(),
3008+
label: largeLabel,
3009+
suffixIcon: Icon(Icons.align_horizontal_left_sharp),
3010+
prefixIcon: Icon(Icons.align_horizontal_right_sharp),
3011+
),
3012+
),
3013+
);
3014+
3015+
expect(getCustomLabelRect(tester).left, affixesHorizontalPadding);
3016+
expect(getCustomLabelRect(tester).right, 800 - affixesHorizontalPadding);
3017+
});
3018+
29543019
testWidgets(
29553020
'The label appears above the input when there is no content and floatingLabelBehavior is always',
29563021
(WidgetTester tester) async {
@@ -8770,15 +8835,19 @@ void main() {
87708835
'Flutter is Google’s UI toolkit for building beautiful, natively compiled applications for mobile, web, and desktop from a single codebase.';
87718836

87728837
Widget getLabeledInputDecorator(FloatingLabelBehavior floatingLabelBehavior) => MaterialApp(
8773-
home: Material(
8774-
child: SizedBox(
8775-
width: 300,
8776-
child: TextField(
8777-
decoration: InputDecoration(
8778-
border: const OutlineInputBorder(borderSide: BorderSide(color: Colors.greenAccent)),
8779-
suffixIcon: const Icon(Icons.arrow_drop_down),
8780-
floatingLabelBehavior: floatingLabelBehavior,
8781-
labelText: labelText,
8838+
home: MaterialApp(
8839+
home: Scaffold(
8840+
body: SizedBox(
8841+
width: 300,
8842+
child: TextField(
8843+
decoration: InputDecoration(
8844+
border: const OutlineInputBorder(
8845+
borderSide: BorderSide(color: Colors.greenAccent),
8846+
),
8847+
suffixIcon: const Icon(Icons.arrow_drop_down),
8848+
floatingLabelBehavior: floatingLabelBehavior,
8849+
labelText: labelText,
8850+
),
87828851
),
87838852
),
87848853
),

0 commit comments

Comments
 (0)