Skip to content

Commit fe7d01f

Browse files
Prevent InputDecorator from supplying its descendants with non-normalized constraints (#130460)
Fixes flutter/flutter#129611
1 parent d0bb56f commit fe7d01f

2 files changed

Lines changed: 44 additions & 16 deletions

File tree

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -964,7 +964,7 @@ class _RenderDecoration extends RenderBox with SlottedContainerRenderObjectMixin
964964
boxToBaseline[prefixIcon] = _layoutLineBox(prefixIcon, containerConstraints);
965965
boxToBaseline[suffixIcon] = _layoutLineBox(suffixIcon, containerConstraints);
966966
final BoxConstraints contentConstraints = containerConstraints.copyWith(
967-
maxWidth: containerConstraints.maxWidth - contentPadding.horizontal,
967+
maxWidth: math.max(0.0, containerConstraints.maxWidth - contentPadding.horizontal),
968968
);
969969
boxToBaseline[prefix] = _layoutLineBox(prefix, contentConstraints);
970970
boxToBaseline[suffix] = _layoutLineBox(suffix, contentConstraints);
@@ -1093,7 +1093,7 @@ class _RenderDecoration extends RenderBox with SlottedContainerRenderObjectMixin
10931093
final double minContainerHeight = decoration.isDense! || decoration.isCollapsed || expands
10941094
? 0.0
10951095
: kMinInteractiveDimension;
1096-
final double maxContainerHeight = boxConstraints.maxHeight - bottomHeight;
1096+
final double maxContainerHeight = math.max(0.0, boxConstraints.maxHeight - bottomHeight);
10971097
final double containerHeight = expands
10981098
? maxContainerHeight
10991099
: math.min(math.max(contentHeight, minContainerHeight), maxContainerHeight);

packages/flutter/test/material/input_decorator_test.dart

Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,11 @@ TextStyle? getIconStyle(WidgetTester tester, IconData icon) {
158158
}
159159

160160
void main() {
161-
for (final bool useMaterial3 in <bool>[true, false]){
161+
runAllTests(useMaterial3: true);
162+
runAllTests(useMaterial3: false);
163+
}
164+
165+
void runAllTests({ required bool useMaterial3 }) {
162166
testWidgets('InputDecorator input/label text layout', (WidgetTester tester) async {
163167
// The label appears above the input text
164168
await tester.pumpWidget(
@@ -1796,7 +1800,7 @@ void main() {
17961800
),
17971801
);
17981802
await tester.pumpWidget(
1799-
MaterialApp(
1803+
MaterialApp(
18001804
theme: theme,
18011805
home: Material(
18021806
child: TextField(
@@ -2011,9 +2015,9 @@ void main() {
20112015

20122016
// Overall height for this InputDecorator is 48dps because the prefix icon's minimum size
20132017
// is 48x48 and the rest of the elements only require 40dps:
2014-
// 12 - top padding
2015-
// 16 - input text (font size 16dps)
2016-
// 12 - bottom padding
2018+
// 12 - top padding
2019+
// 16 - input text (font size 16dps)
2020+
// 12 - bottom padding
20172021

20182022
expect(tester.getSize(find.byType(InputDecorator)), const Size(800.0, 48.0));
20192023
expect(tester.getSize(find.text('text')).height, 16.0);
@@ -2085,10 +2089,10 @@ void main() {
20852089
);
20862090

20872091
// Overall height for this InputDecorator is 48dps because the prefix icon's minimum size
2088-
// is 48x48 and the rest of the elements only require 40dps:
2089-
// 12 - top padding
2090-
// 16 - input text (font size 16dps)
2091-
// 12 - bottom padding
2092+
// is 48x48 and the rest of the elements only require 40dps:
2093+
// 12 - top padding
2094+
// 16 - input text (font size 16dps)
2095+
// 12 - bottom padding
20922096

20932097
expect(tester.getSize(find.byType(InputDecorator)), const Size(800.0, 48.0));
20942098
expect(tester.getSize(find.byKey(prefixKey)).height, 16.0);
@@ -2303,9 +2307,9 @@ void main() {
23032307

23042308
// Overall height for this InputDecorator is 100dps because the prefix icon's size
23052309
// is 100x100 and the rest of the elements only require 40dps:
2306-
// 12 - top padding
2307-
// 16 - input text (font size 16dps)
2308-
// 12 - bottom padding
2310+
// 12 - top padding
2311+
// 16 - input text (font size 16dps)
2312+
// 12 - bottom padding
23092313

23102314
expect(tester.getSize(find.byType(InputDecorator)), const Size(800.0, 100.0));
23112315
expect(tester.getSize(find.byKey(prefixKey)).height, 100.0);
@@ -5487,7 +5491,7 @@ void main() {
54875491
);
54885492
}, skip: isBrowser); // https://github.com/flutter/flutter/issues/55317
54895493

5490-
testWidgets('OutlineInputBorder with BorderRadius.zero should draw a rectangular border', (WidgetTester tester) async {
5494+
testWidgets('OutlineInputBorder with BorderRadius.zero should draw a rectangular border', (WidgetTester tester) async {
54915495
// Regression test for https://github.com/flutter/flutter/issues/78855
54925496
const String labelText = 'Flutter';
54935497

@@ -6546,5 +6550,29 @@ void main() {
65466550
// The prefix is inside the decorator.
65476551
expect(decoratorRight, lessThanOrEqualTo(prefixRight));
65486552
});
6549-
}
6553+
6554+
testWidgets('InputDecorator with counter does not crash when given a 0 size', (WidgetTester tester) async {
6555+
// Regression test for https://github.com/flutter/flutter/issues/129611
6556+
const InputDecoration decoration = InputDecoration(
6557+
contentPadding: EdgeInsetsDirectional.all(99),
6558+
prefixIcon: Focus(child: Icon(Icons.search)),
6559+
counter: Text('COUNTER'),
6560+
);
6561+
6562+
await tester.pumpWidget(
6563+
Center(
6564+
child: SizedBox.square(
6565+
dimension: 0.0,
6566+
child: buildInputDecorator(
6567+
useMaterial3: useMaterial3,
6568+
decoration: decoration,
6569+
),
6570+
),
6571+
),
6572+
);
6573+
await tester.pumpAndSettle();
6574+
6575+
expect(find.byType(InputDecorator), findsOneWidget);
6576+
expect(tester.renderObject<RenderBox>(find.text('COUNTER')).size, Size.zero);
6577+
});
65506578
}

0 commit comments

Comments
 (0)