Add minimum height and width box constraints to input decoration icons (#18480)
This commit is contained in:
parent
2a19dae28b
commit
24a1f57065
@ -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
|
|||||||
);
|
);
|
||||||
|
|
||||||
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
|
|||||||
|
|
||||||
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
|
|||||||
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
|
|||||||
} 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 {
|
|||||||
/// [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 {
|
|||||||
/// [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() {
|
|||||||
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(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user