Unverified Commit daa16199 authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

Fix input decoration height and margin calculation. (#18696)

parent a7ba7b4b
......@@ -803,9 +803,6 @@ class _RenderDecoration extends RenderBox {
+ aboveBaseline
+ belowBaseline
+ contentPadding.bottom;
containerHeight = math.max(
containerHeight,
math.max(_boxSize(suffixIcon).height, _boxSize(prefixIcon).height));
if (label != null) {
// floatingLabelHeight includes the vertical gap between the inline
......@@ -814,6 +811,12 @@ class _RenderDecoration extends RenderBox {
inputBaseline += decoration.floatingLabelHeight;
}
containerHeight = math.max(
containerHeight,
math.max(
_boxSize(suffixIcon).height,
_boxSize(prefixIcon).height));
// Inline text within an outline border is centered within the container
// less 2.0 dps at the top to account for the vertical space occupied
// by the floating label.
......@@ -982,8 +985,10 @@ class _RenderDecoration extends RenderBox {
case TextDirection.rtl: {
double start = right - _boxSize(icon).width;
double end = left;
if (prefixIcon != null)
if (prefixIcon != null) {
start += contentPadding.left;
start -= centerLayout(prefixIcon, start - prefixIcon.size.width);
}
if (label != null)
centerLayout(label, start - label.size.width);
if (prefix != null)
......@@ -992,8 +997,10 @@ class _RenderDecoration extends RenderBox {
baselineLayout(input, start - input.size.width);
if (hint != null)
baselineLayout(hint, start - hint.size.width);
if (suffixIcon != null)
if (suffixIcon != null) {
end -= contentPadding.left;
end += centerLayout(suffixIcon, end);
}
if (suffix != null)
end += baselineLayout(suffix, end);
break;
......@@ -1001,8 +1008,10 @@ class _RenderDecoration extends RenderBox {
case TextDirection.ltr: {
double start = left + _boxSize(icon).width;
double end = right;
if (prefixIcon != null)
if (prefixIcon != null) {
start -= contentPadding.left;
start += centerLayout(prefixIcon, start);
}
if (label != null)
centerLayout(label, start);
if (prefix != null)
......@@ -1011,8 +1020,10 @@ class _RenderDecoration extends RenderBox {
baselineLayout(input, start);
if (hint != null)
baselineLayout(hint, start);
if (suffixIcon != null)
if (suffixIcon != null) {
end += contentPadding.right;
end -= centerLayout(suffixIcon, end - suffixIcon.size.width);
}
if (suffix != null)
end -= baselineLayout(suffix, end - suffix.size.width);
break;
......@@ -1691,26 +1702,34 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
);
final Widget prefixIcon = decoration.prefixIcon == null ? null :
new ConstrainedBox(
constraints: const BoxConstraints(minWidth: 48.0, minHeight: 48.0),
child: IconTheme.merge(
data: new IconThemeData(
color: iconColor,
size: iconSize,
new Center(
widthFactor: 1.0,
heightFactor: 1.0,
child: new ConstrainedBox(
constraints: const BoxConstraints(minWidth: 48.0, minHeight: 48.0),
child: IconTheme.merge(
data: new IconThemeData(
color: iconColor,
size: iconSize,
),
child: decoration.prefixIcon,
),
child: decoration.prefixIcon,
),
);
final Widget suffixIcon = decoration.suffixIcon == null ? null :
new ConstrainedBox(
constraints: const BoxConstraints(minWidth: 48.0, minHeight: 48.0),
child: IconTheme.merge(
data: new IconThemeData(
color: iconColor,
size: iconSize,
new Center(
widthFactor: 1.0,
heightFactor: 1.0,
child: ConstrainedBox(
constraints: const BoxConstraints(minWidth: 48.0, minHeight: 48.0),
child: IconTheme.merge(
data: new IconThemeData(
color: iconColor,
size: iconSize,
),
child: decoration.suffixIcon,
),
child: decoration.suffixIcon,
),
);
......@@ -1737,8 +1756,6 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
EdgeInsets contentPadding;
double floatingLabelHeight;
final double leftInset = decoration.prefixIcon == null ? 12.0 : 0.0;
final double rightInset = decoration.suffixIcon == null ? 12.0 : 0.0;
if (decoration.isCollapsed) {
floatingLabelHeight = 0.0;
contentPadding = decorationContentPadding ?? EdgeInsets.zero;
......@@ -1747,8 +1764,8 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
floatingLabelHeight = 4.0 + 0.75 * inlineLabelStyle.fontSize;
if (decoration.filled == true) { // filled == null same as filled == false
contentPadding = decorationContentPadding ?? (decorationIsDense
? new EdgeInsets.fromLTRB(leftInset, 8.0, rightInset, 8.0)
: new EdgeInsets.fromLTRB(leftInset, 12.0, rightInset, 12.0));
? const EdgeInsets.fromLTRB(12.0, 8.0, 12.0, 8.0)
: const EdgeInsets.fromLTRB(12.0, 12.0, 12.0, 12.0));
} else {
// Not left or right padding for underline borders that aren't filled
// is a small concession to backwards compatibility. This eliminates
......@@ -1760,10 +1777,9 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
} else {
floatingLabelHeight = 0.0;
contentPadding = decorationContentPadding ?? (decorationIsDense
? new EdgeInsets.fromLTRB(leftInset, 20.0, rightInset, 12.0)
: new EdgeInsets.fromLTRB(leftInset, 24.0, rightInset, 16.0));
? const EdgeInsets.fromLTRB(12.0, 20.0, 12.0, 12.0)
: const EdgeInsets.fromLTRB(12.0, 24.0, 12.0, 16.0));
}
return new _Decorator(
decoration: new _Decoration(
contentPadding: contentPadding,
......
......@@ -763,12 +763,11 @@ void main() {
),
);
// Overall height for this InputDecorator is 48dps:
// 12 - top padding
// 16 - input text (ahem font size 16dps)
// 12 - bottom padding
// 48 - prefix icon
// 48 - suffix icon
// Overall height for this InputDecorator is 48dps because the prefix icon's minimum size
// is 48x48 and the rest of the elements only require 40dps:
// 12 - top padding
// 16 - input text (ahem font size 16dps)
// 12 - bottom padding
expect(tester.getSize(find.byType(InputDecorator)), const Size(800.0, 48.0));
expect(tester.getSize(find.text('text')).height, 16.0);
......@@ -786,6 +785,132 @@ void main() {
expect(tester.getTopRight(find.text('text')).dx, lessThanOrEqualTo(tester.getTopLeft(find.byIcon(Icons.satellite)).dx));
});
testWidgets('prefix/suffix icons are centered when smaller than 48 by 48', (WidgetTester tester) async {
const Key prefixKey = const Key('prefix');
await tester.pumpWidget(
buildInputDecorator(
decoration: const InputDecoration(
prefixIcon: const Padding(
padding: const EdgeInsets.all(16.0),
child: const SizedBox(width: 8.0, height: 8.0, key: prefixKey),
),
filled: true,
),
),
);
// Overall height for this InputDecorator is 48dps because the prefix icon's minimum size
// is 48x48 and the rest of the elements only require 40dps:
// 12 - top padding
// 16 - input text (ahem font size 16dps)
// 12 - bottom padding
expect(tester.getSize(find.byType(InputDecorator)), const Size(800.0, 48.0));
expect(tester.getSize(find.byKey(prefixKey)).height, 16.0);
expect(tester.getTopLeft(find.byKey(prefixKey)).dy, 16.0);
});
testWidgets('prefix/suffix icons increase height of decoration when larger than 48 by 48', (WidgetTester tester) async {
const Key prefixKey = const Key('prefix');
await tester.pumpWidget(
buildInputDecorator(
decoration: const InputDecoration(
prefixIcon: const SizedBox(width: 100.0, height: 100.0, key: prefixKey),
filled: true,
),
),
);
// Overall height for this InputDecorator is 100dps because the prefix icon's size
// is 100x100 and the rest of the elements only require 40dps:
// 12 - top padding
// 16 - input text (ahem font size 16dps)
// 12 - bottom padding
expect(tester.getSize(find.byType(InputDecorator)), const Size(800.0, 100.0));
expect(tester.getSize(find.byKey(prefixKey)).height, 100.0);
expect(tester.getTopLeft(find.byKey(prefixKey)).dy, 0.0);
});
testWidgets('counter text has correct right margin - LTR, not dense', (WidgetTester tester) async {
await tester.pumpWidget(
buildInputDecorator(
// isEmpty: false (default)
// isFocused: false (default)
decoration: const InputDecoration(
counterText: 'test',
filled: true,
),
),
);
// Margin for text decoration is 12 when filled
// (dx) - 12 = (text offset)x.
expect(tester.getSize(find.byType(InputDecorator)), const Size(800.0, 60.0));
final double dx = tester.getRect(find.byType(InputDecorator)).right;
expect(tester.getRect(find.text('test')).right, dx - 12.0);
});
testWidgets('counter text has correct right margin - RTL, not dense', (WidgetTester tester) async {
await tester.pumpWidget(
buildInputDecorator(
textDirection: TextDirection.rtl,
// isEmpty: false (default)
// isFocused: false (default)
decoration: const InputDecoration(
counterText: 'test',
filled: true,
),
),
);
// Margin for text decoration is 12 when filled and top left offset is (0, 0)
// 0 + 12 = 12.
expect(tester.getSize(find.byType(InputDecorator)), const Size(800.0, 60.0));
expect(tester.getRect(find.text('test')).left, 12.0);
});
testWidgets('counter text has correct right margin - LTR, dense', (WidgetTester tester) async {
await tester.pumpWidget(
buildInputDecorator(
// isEmpty: false (default)
// isFocused: false (default)
decoration: const InputDecoration(
counterText: 'test',
filled: true,
isDense: true,
),
),
);
// Margin for text decoration is 12 when filled
// (dx) - 12 = (text offset)x.
expect(tester.getSize(find.byType(InputDecorator)), const Size(800.0, 52.0));
final double dx = tester.getRect(find.byType(InputDecorator)).right;
expect(tester.getRect(find.text('test')).right, dx - 12.0);
});
testWidgets('counter text has correct right margin - RTL, dense', (WidgetTester tester) async {
await tester.pumpWidget(
buildInputDecorator(
textDirection: TextDirection.rtl,
// isEmpty: false (default)
// isFocused: false (default)
decoration: const InputDecoration(
counterText: 'test',
filled: true,
isDense: true,
),
),
);
// Margin for text decoration is 12 when filled and top left offset is (0, 0)
// 0 + 12 = 12.
expect(tester.getSize(find.byType(InputDecorator)), const Size(800.0, 52.0));
expect(tester.getRect(find.text('test')).left, 12.0);
});
testWidgets('InputDecorator error/helper/counter RTL layout', (WidgetTester tester) async {
await tester.pumpWidget(
buildInputDecorator(
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment