Improve the layout/sizing of InputDecorator
This commit is contained in:
parent
f10f3e79a6
commit
93de90bc26
1
AUTHORS
1
AUTHORS
@ -83,3 +83,4 @@ Mirko Mucaria <skogsfrae@gmail.com>
|
|||||||
Karol Czeryna <karol.czeryna@gmail.com>
|
Karol Czeryna <karol.czeryna@gmail.com>
|
||||||
Callum Moffat <callum@moffatman.com>
|
Callum Moffat <callum@moffatman.com>
|
||||||
Koutaro Mori <koutaro.mo@gmail.com>
|
Koutaro Mori <koutaro.mo@gmail.com>
|
||||||
|
Sergei Smitskoi <sergflutterdev@gmail.com>
|
||||||
|
@ -971,11 +971,17 @@ class _RenderDecoration extends RenderBox {
|
|||||||
final BoxConstraints boxConstraints = layoutConstraints.loosen();
|
final BoxConstraints boxConstraints = layoutConstraints.loosen();
|
||||||
|
|
||||||
// Layout all the widgets used by InputDecorator
|
// Layout all the widgets used by InputDecorator
|
||||||
boxToBaseline[prefix] = _layoutLineBox(prefix, boxConstraints);
|
|
||||||
boxToBaseline[suffix] = _layoutLineBox(suffix, boxConstraints);
|
|
||||||
boxToBaseline[icon] = _layoutLineBox(icon, boxConstraints);
|
boxToBaseline[icon] = _layoutLineBox(icon, boxConstraints);
|
||||||
boxToBaseline[prefixIcon] = _layoutLineBox(prefixIcon, boxConstraints);
|
final BoxConstraints containerConstraints = boxConstraints.copyWith(
|
||||||
boxToBaseline[suffixIcon] = _layoutLineBox(suffixIcon, boxConstraints);
|
maxWidth: boxConstraints.maxWidth - _boxSize(icon).width,
|
||||||
|
);
|
||||||
|
boxToBaseline[prefixIcon] = _layoutLineBox(prefixIcon, containerConstraints);
|
||||||
|
boxToBaseline[suffixIcon] = _layoutLineBox(suffixIcon, containerConstraints);
|
||||||
|
final BoxConstraints contentConstraints = containerConstraints.copyWith(
|
||||||
|
maxWidth: containerConstraints.maxWidth - contentPadding.horizontal,
|
||||||
|
);
|
||||||
|
boxToBaseline[prefix] = _layoutLineBox(prefix, contentConstraints);
|
||||||
|
boxToBaseline[suffix] = _layoutLineBox(suffix, contentConstraints);
|
||||||
|
|
||||||
final double inputWidth = math.max(
|
final double inputWidth = math.max(
|
||||||
0.0,
|
0.0,
|
||||||
@ -1011,18 +1017,14 @@ class _RenderDecoration extends RenderBox {
|
|||||||
hint,
|
hint,
|
||||||
boxConstraints.copyWith(minWidth: inputWidth, maxWidth: inputWidth),
|
boxConstraints.copyWith(minWidth: inputWidth, maxWidth: inputWidth),
|
||||||
);
|
);
|
||||||
boxToBaseline[counter] = _layoutLineBox(counter, boxConstraints);
|
boxToBaseline[counter] = _layoutLineBox(counter, contentConstraints);
|
||||||
|
|
||||||
// The helper or error text can occupy the full width less the space
|
// The helper or error text can occupy the full width less the space
|
||||||
// occupied by the icon and counter.
|
// occupied by the icon and counter.
|
||||||
boxToBaseline[helperError] = _layoutLineBox(
|
boxToBaseline[helperError] = _layoutLineBox(
|
||||||
helperError,
|
helperError,
|
||||||
boxConstraints.copyWith(
|
contentConstraints.copyWith(
|
||||||
maxWidth: math.max(0.0, boxConstraints.maxWidth
|
maxWidth: math.max(0.0, contentConstraints.maxWidth - _boxSize(counter).width),
|
||||||
- _boxSize(icon).width
|
|
||||||
- _boxSize(counter).width
|
|
||||||
- contentPadding.horizontal,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -1267,15 +1269,45 @@ class _RenderDecoration extends RenderBox {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
double computeMinIntrinsicHeight(double width) {
|
double computeMinIntrinsicHeight(double width) {
|
||||||
double subtextHeight = _lineHeight(width, <RenderBox?>[helperError, counter]);
|
final double iconHeight = _minHeight(icon, width);
|
||||||
|
final double iconWidth = _minWidth(icon, iconHeight);
|
||||||
|
|
||||||
|
width = math.max(width - iconWidth, 0.0);
|
||||||
|
|
||||||
|
final double prefixIconHeight = _minHeight(prefixIcon, width);
|
||||||
|
final double prefixIconWidth = _minWidth(prefixIcon, prefixIconHeight);
|
||||||
|
|
||||||
|
final double suffixIconHeight = _minHeight(suffixIcon, width);
|
||||||
|
final double suffixIconWidth = _minWidth(suffixIcon, suffixIconHeight);
|
||||||
|
|
||||||
|
width = math.max(width - contentPadding.horizontal, 0.0);
|
||||||
|
|
||||||
|
final double counterHeight = _minHeight(counter, width);
|
||||||
|
final double counterWidth = _minWidth(counter, counterHeight);
|
||||||
|
|
||||||
|
final double helperErrorAvailableWidth = math.max(width - counterWidth, 0.0);
|
||||||
|
final double helperErrorHeight = _minHeight(helperError, helperErrorAvailableWidth);
|
||||||
|
double subtextHeight = math.max(counterHeight, helperErrorHeight);
|
||||||
if (subtextHeight > 0.0)
|
if (subtextHeight > 0.0)
|
||||||
subtextHeight += subtextGap;
|
subtextHeight += subtextGap;
|
||||||
|
|
||||||
|
final double prefixHeight = _minHeight(prefix, width);
|
||||||
|
final double prefixWidth = _minWidth(prefix, prefixHeight);
|
||||||
|
|
||||||
|
final double suffixHeight = _minHeight(suffix, width);
|
||||||
|
final double suffixWidth = _minWidth(suffix, suffixHeight);
|
||||||
|
|
||||||
|
final double availableInputWidth = math.max(width - prefixWidth - suffixWidth - prefixIconWidth - suffixIconWidth, 0.0);
|
||||||
|
final double inputHeight = _lineHeight(availableInputWidth, <RenderBox?>[input, hint]);
|
||||||
|
final double inputMaxHeight = <double>[inputHeight, prefixHeight, suffixHeight].reduce(math.max);
|
||||||
|
|
||||||
final Offset densityOffset = decoration.visualDensity!.baseSizeAdjustment;
|
final Offset densityOffset = decoration.visualDensity!.baseSizeAdjustment;
|
||||||
final double containerHeight = contentPadding.top
|
final double contentHeight = contentPadding.top
|
||||||
+ (label == null ? 0.0 : decoration.floatingLabelHeight)
|
+ (label == null ? 0.0 : decoration.floatingLabelHeight)
|
||||||
+ _lineHeight(width, <RenderBox?>[prefix, input, suffix])
|
+ inputMaxHeight
|
||||||
+ contentPadding.bottom
|
+ contentPadding.bottom
|
||||||
+ densityOffset.dy;
|
+ densityOffset.dy;
|
||||||
|
final double containerHeight = <double>[iconHeight, contentHeight, prefixIconHeight, suffixIconHeight].reduce(math.max);
|
||||||
final double minContainerHeight = decoration.isDense! || expands
|
final double minContainerHeight = decoration.isDense! || expands
|
||||||
? 0.0
|
? 0.0
|
||||||
: kMinInteractiveDimension;
|
: kMinInteractiveDimension;
|
||||||
|
@ -5023,6 +5023,146 @@ void main() {
|
|||||||
expect(tester.takeException(), isNull);
|
expect(tester.takeException(), isNull);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('min intrinsic height for TextField with prefix icon', (WidgetTester tester) async {
|
||||||
|
// Regression test for: https://github.com/flutter/flutter/issues/87403
|
||||||
|
await tester.pumpWidget(MaterialApp(
|
||||||
|
home: Material(
|
||||||
|
child: Center(
|
||||||
|
child: SizedBox(
|
||||||
|
width: 100.0,
|
||||||
|
child: IntrinsicHeight(
|
||||||
|
child: Column(
|
||||||
|
children: <Widget>[
|
||||||
|
TextField(
|
||||||
|
controller: TextEditingController(text: 'input'),
|
||||||
|
maxLines: null,
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
prefixIcon: Icon(Icons.search),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
expect(tester.takeException(), isNull);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('min intrinsic height for TextField with suffix icon', (WidgetTester tester) async {
|
||||||
|
// Regression test for: https://github.com/flutter/flutter/issues/87403
|
||||||
|
await tester.pumpWidget(MaterialApp(
|
||||||
|
home: Material(
|
||||||
|
child: Center(
|
||||||
|
child: SizedBox(
|
||||||
|
width: 100.0,
|
||||||
|
child: IntrinsicHeight(
|
||||||
|
child: Column(
|
||||||
|
children: <Widget>[
|
||||||
|
TextField(
|
||||||
|
controller: TextEditingController(text: 'input'),
|
||||||
|
maxLines: null,
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
suffixIcon: Icon(Icons.search),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
expect(tester.takeException(), isNull);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('min intrinsic height for TextField with prefix', (WidgetTester tester) async {
|
||||||
|
// Regression test for: https://github.com/flutter/flutter/issues/87403
|
||||||
|
await tester.pumpWidget(MaterialApp(
|
||||||
|
home: Material(
|
||||||
|
child: Center(
|
||||||
|
child: SizedBox(
|
||||||
|
width: 100.0,
|
||||||
|
child: IntrinsicHeight(
|
||||||
|
child: Column(
|
||||||
|
children: <Widget>[
|
||||||
|
TextField(
|
||||||
|
controller: TextEditingController(text: 'input'),
|
||||||
|
maxLines: null,
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
prefix: Text('prefix'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
expect(tester.takeException(), isNull);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('min intrinsic height for TextField with suffix', (WidgetTester tester) async {
|
||||||
|
// Regression test for: https://github.com/flutter/flutter/issues/87403
|
||||||
|
await tester.pumpWidget(MaterialApp(
|
||||||
|
home: Material(
|
||||||
|
child: Center(
|
||||||
|
child: SizedBox(
|
||||||
|
width: 100.0,
|
||||||
|
child: IntrinsicHeight(
|
||||||
|
child: Column(
|
||||||
|
children: <Widget>[
|
||||||
|
TextField(
|
||||||
|
controller: TextEditingController(text: 'input'),
|
||||||
|
maxLines: null,
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
suffix: Text('suffix'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
expect(tester.takeException(), isNull);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('min intrinsic height for TextField with icon', (WidgetTester tester) async {
|
||||||
|
// Regression test for: https://github.com/flutter/flutter/issues/87403
|
||||||
|
await tester.pumpWidget(MaterialApp(
|
||||||
|
home: Material(
|
||||||
|
child: Center(
|
||||||
|
child: SizedBox(
|
||||||
|
width: 100.0,
|
||||||
|
child: IntrinsicHeight(
|
||||||
|
child: Column(
|
||||||
|
children: <Widget>[
|
||||||
|
TextField(
|
||||||
|
controller: TextEditingController(text: 'input'),
|
||||||
|
maxLines: null,
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
icon: Icon(Icons.search),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
expect(tester.takeException(), isNull);
|
||||||
|
});
|
||||||
|
|
||||||
testWidgets('InputDecorationTheme floatingLabelStyle overrides label widget styles when the widget is a text widget (focused)', (WidgetTester tester) async {
|
testWidgets('InputDecorationTheme floatingLabelStyle overrides label widget styles when the widget is a text widget (focused)', (WidgetTester tester) async {
|
||||||
const TextStyle style16 = TextStyle(fontFamily: 'Ahem', fontSize: 16.0);
|
const TextStyle style16 = TextStyle(fontFamily: 'Ahem', fontSize: 16.0);
|
||||||
final TextStyle floatingLabelStyle = style16.merge(const TextStyle(color: Colors.indigo));
|
final TextStyle floatingLabelStyle = style16.merge(const TextStyle(color: Colors.indigo));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user