Unverified Commit 24a1f570 authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

Add minimum height and width box constraints to input decoration icons (#18480)

parent 2a19dae2
...@@ -803,6 +803,9 @@ class _RenderDecoration extends RenderBox { ...@@ -803,6 +803,9 @@ class _RenderDecoration extends RenderBox {
+ aboveBaseline + aboveBaseline
+ belowBaseline + belowBaseline
+ contentPadding.bottom; + contentPadding.bottom;
containerHeight = math.max(
containerHeight,
math.max(_boxSize(suffixIcon).height, _boxSize(prefixIcon).height));
if (label != null) { if (label != null) {
// floatingLabelHeight includes the vertical gap between the inline // floatingLabelHeight includes the vertical gap between the inline
...@@ -1688,21 +1691,27 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat ...@@ -1688,21 +1691,27 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
); );
final Widget prefixIcon = decoration.prefixIcon == null ? null : final Widget prefixIcon = decoration.prefixIcon == null ? null :
IconTheme.merge( new ConstrainedBox(
data: new IconThemeData( constraints: const BoxConstraints(minWidth: 48.0, minHeight: 48.0),
color: iconColor, child: IconTheme.merge(
size: iconSize, data: new IconThemeData(
color: iconColor,
size: iconSize,
),
child: decoration.prefixIcon,
), ),
child: decoration.prefixIcon,
); );
final Widget suffixIcon = decoration.suffixIcon == null ? null : final Widget suffixIcon = decoration.suffixIcon == null ? null :
IconTheme.merge( new ConstrainedBox(
data: new IconThemeData( constraints: const BoxConstraints(minWidth: 48.0, minHeight: 48.0),
color: iconColor, child: IconTheme.merge(
size: iconSize, data: new IconThemeData(
color: iconColor,
size: iconSize,
),
child: decoration.suffixIcon,
), ),
child: decoration.suffixIcon,
); );
final Widget helperError = new _HelperError( final Widget helperError = new _HelperError(
...@@ -1728,6 +1737,8 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat ...@@ -1728,6 +1737,8 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
EdgeInsets contentPadding; EdgeInsets contentPadding;
double floatingLabelHeight; 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) { if (decoration.isCollapsed) {
floatingLabelHeight = 0.0; floatingLabelHeight = 0.0;
contentPadding = decorationContentPadding ?? EdgeInsets.zero; contentPadding = decorationContentPadding ?? EdgeInsets.zero;
...@@ -1736,8 +1747,8 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat ...@@ -1736,8 +1747,8 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
floatingLabelHeight = 4.0 + 0.75 * inlineLabelStyle.fontSize; floatingLabelHeight = 4.0 + 0.75 * inlineLabelStyle.fontSize;
if (decoration.filled == true) { // filled == null same as filled == false if (decoration.filled == true) { // filled == null same as filled == false
contentPadding = decorationContentPadding ?? (decorationIsDense contentPadding = decorationContentPadding ?? (decorationIsDense
? const EdgeInsets.fromLTRB(12.0, 8.0, 12.0, 8.0) ? new EdgeInsets.fromLTRB(leftInset, 8.0, rightInset, 8.0)
: const EdgeInsets.fromLTRB(12.0, 12.0, 12.0, 12.0)); : new EdgeInsets.fromLTRB(leftInset, 12.0, rightInset, 12.0));
} else { } else {
// Not left or right padding for underline borders that aren't filled // Not left or right padding for underline borders that aren't filled
// is a small concession to backwards compatibility. This eliminates // is a small concession to backwards compatibility. This eliminates
...@@ -1749,8 +1760,8 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat ...@@ -1749,8 +1760,8 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
} else { } else {
floatingLabelHeight = 0.0; floatingLabelHeight = 0.0;
contentPadding = decorationContentPadding ?? (decorationIsDense contentPadding = decorationContentPadding ?? (decorationIsDense
? const EdgeInsets.fromLTRB(12.0, 20.0, 12.0, 12.0) ? new EdgeInsets.fromLTRB(leftInset, 20.0, rightInset, 12.0)
: const EdgeInsets.fromLTRB(12.0, 24.0, 12.0, 16.0)); : new EdgeInsets.fromLTRB(leftInset, 24.0, rightInset, 16.0));
} }
return new _Decorator( return new _Decorator(
...@@ -1987,11 +1998,16 @@ class InputDecoration { ...@@ -1987,11 +1998,16 @@ class InputDecoration {
/// [IconTheme] and therefore does not need to be explicitly given in the /// [IconTheme] and therefore does not need to be explicitly given in the
/// icon widget. /// icon widget.
/// ///
/// The prefix icon is not padded. To pad the trailing edge of the prefix icon: /// The prefix icon is constrained with a minimum size of 48px by 48px, but
/// can be expanded beyond that. Anything larger than 24px will require
/// additional padding to ensure it matches the material spec of 12px padding
/// between the left edge of the input and leading edge of the prefix icon.
/// To pad the leading edge of the prefix icon:
///
/// ```dart /// ```dart
/// prefixIcon: new Padding( /// prefixIcon: new Padding(
/// padding: const EdgeInsetsDirectional.only(end: 16.0), /// padding: const EdgeInsetsDirectional.only(start: 12.0),
/// child: myIcon, /// child: myIcon, // icon is 48px widget.
/// ) /// )
/// ``` /// ```
/// ///
...@@ -2021,11 +2037,16 @@ class InputDecoration { ...@@ -2021,11 +2037,16 @@ class InputDecoration {
/// [IconTheme] and therefore does not need to be explicitly given in the /// [IconTheme] and therefore does not need to be explicitly given in the
/// icon widget. /// icon widget.
/// ///
/// The suffix icon is not padded. To pad the leading edge of the suffix icon: /// The suffix icon is constrained with a minimum size of 48px by 48px, but
/// can be expanded beyond that. Anything larger than 24px will require
/// additional padding to ensure it matches the material spec of 12px padding
/// between the right edge of the input and trailing edge of the prefix icon.
/// To pad the trailing edge of the suffix icon:
///
/// ```dart /// ```dart
/// suffixIcon: new Padding( /// suffixIcon: new Padding(
/// padding: const EdgeInsetsDirectional.only(start: 16.0), /// padding: const EdgeInsetsDirectional.only(end: 12.0),
/// child: new Icon(Icons.search), /// child: myIcon, // icon is 48px widget.
/// ) /// )
/// ``` /// ```
/// ///
......
...@@ -750,6 +750,42 @@ void main() { ...@@ -750,6 +750,42 @@ void main() {
expect(tester.getTopRight(find.text('text')).dx, lessThanOrEqualTo(tester.getTopLeft(find.text('s')).dx)); expect(tester.getTopRight(find.text('text')).dx, lessThanOrEqualTo(tester.getTopLeft(find.text('s')).dx));
}); });
testWidgets('InputDecorator prefixIcon/suffixIcon', (WidgetTester tester) async {
await tester.pumpWidget(
buildInputDecorator(
// isEmpty: false (default)
// isFocused: false (default)
decoration: const InputDecoration(
prefixIcon: const Icon(Icons.pages),
suffixIcon: const Icon(Icons.satellite),
filled: true,
),
),
);
// 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
expect(tester.getSize(find.byType(InputDecorator)), const Size(800.0, 48.0));
expect(tester.getSize(find.text('text')).height, 16.0);
expect(tester.getSize(find.byIcon(Icons.pages)).height, 48.0);
expect(tester.getSize(find.byIcon(Icons.satellite)).height, 48.0);
expect(tester.getTopLeft(find.text('text')).dy, 12.0);
expect(tester.getTopLeft(find.byIcon(Icons.pages)).dy, 0.0);
expect(tester.getTopLeft(find.byIcon(Icons.satellite)).dy, 0.0);
expect(tester.getTopRight(find.byIcon(Icons.satellite)).dx, 800.0);
// layout is a row: [icon text icon]
expect(tester.getTopLeft(find.byIcon(Icons.pages)).dx, 0.0);
expect(tester.getTopRight(find.byIcon(Icons.pages)).dx, lessThanOrEqualTo(tester.getTopLeft(find.text('text')).dx));
expect(tester.getTopRight(find.text('text')).dx, lessThanOrEqualTo(tester.getTopLeft(find.byIcon(Icons.satellite)).dx));
});
testWidgets('InputDecorator error/helper/counter RTL layout', (WidgetTester tester) async { testWidgets('InputDecorator error/helper/counter RTL layout', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
buildInputDecorator( 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