Revert "Fix TextField height issues (#27205)" (#29093)
This reverts commit 9e9f48dabb8423a6285bddfb21e69f0751060459.
diff --git a/packages/flutter/lib/src/material/input_decorator.dart b/packages/flutter/lib/src/material/input_decorator.dart
index 83f1e12..ca11f11 100644
--- a/packages/flutter/lib/src/material/input_decorator.dart
+++ b/packages/flutter/lib/src/material/input_decorator.dart
@@ -552,16 +552,13 @@
@required TextDirection textDirection,
@required TextBaseline textBaseline,
@required bool isFocused,
- @required bool expands,
}) : assert(decoration != null),
assert(textDirection != null),
assert(textBaseline != null),
- assert(expands != null),
_decoration = decoration,
_textDirection = textDirection,
_textBaseline = textBaseline,
- _isFocused = isFocused,
- _expands = expands;
+ _isFocused = isFocused;
final Map<_DecorationSlot, RenderBox> slotToChild = <_DecorationSlot, RenderBox>{};
final Map<RenderBox, _DecorationSlot> childToSlot = <RenderBox, _DecorationSlot>{};
@@ -712,16 +709,6 @@
markNeedsSemanticsUpdate();
}
- bool get expands => _expands;
- bool _expands = false;
- set expands(bool value) {
- assert(value != null);
- if (_expands == value)
- return;
- _expands = value;
- markNeedsLayout();
- }
-
@override
void attach(PipelineOwner owner) {
super.attach(owner);
@@ -817,31 +804,34 @@
EdgeInsets get contentPadding => decoration.contentPadding;
- // Lay out the given box if needed, and return its baseline
- double _layoutLineBox(RenderBox box, BoxConstraints constraints) {
- if (box == null) {
- return 0.0;
- }
- box.layout(constraints, parentUsesSize: true);
- final double baseline = box.getDistanceToBaseline(textBaseline);
- assert(baseline != null && baseline >= 0.0);
- return baseline;
- }
-
- // Returns a value used by performLayout to position all of the renderers.
- // This method applies layout to all of the renderers except the container.
- // For convenience, the container is laid out in performLayout().
+ // Returns a value used by performLayout to position all
+ // of the renderers. This method applies layout to all of the renderers
+ // except the container. For convenience, the container is laid out
+ // in performLayout().
_RenderDecorationLayout _layout(BoxConstraints layoutConstraints) {
- // Margin on each side of subtext (counter and helperError)
final Map<RenderBox, double> boxToBaseline = <RenderBox, double>{};
- final BoxConstraints boxConstraints = layoutConstraints.loosen();
+ BoxConstraints boxConstraints = layoutConstraints.loosen();
+ double aboveBaseline = 0.0;
+ double belowBaseline = 0.0;
+ void layoutLineBox(RenderBox box) {
+ if (box == null)
+ return;
+ box.layout(boxConstraints, parentUsesSize: true);
+ final double baseline = box.getDistanceToBaseline(textBaseline);
+ assert(baseline != null && baseline >= 0.0);
+ boxToBaseline[box] = baseline;
+ aboveBaseline = math.max(baseline, aboveBaseline);
+ belowBaseline = math.max(box.size.height - baseline, belowBaseline);
+ }
+ layoutLineBox(prefix);
+ layoutLineBox(suffix);
- // Layout all the widgets used by InputDecorator
- boxToBaseline[prefix] = _layoutLineBox(prefix, boxConstraints);
- boxToBaseline[suffix] = _layoutLineBox(suffix, boxConstraints);
- boxToBaseline[icon] = _layoutLineBox(icon, boxConstraints);
- boxToBaseline[prefixIcon] = _layoutLineBox(prefixIcon, boxConstraints);
- boxToBaseline[suffixIcon] = _layoutLineBox(suffixIcon, boxConstraints);
+ if (icon != null)
+ icon.layout(boxConstraints, parentUsesSize: true);
+ if (prefixIcon != null)
+ prefixIcon.layout(boxConstraints, parentUsesSize: true);
+ if (suffixIcon != null)
+ suffixIcon.layout(boxConstraints, parentUsesSize: true);
final double inputWidth = math.max(0.0, constraints.maxWidth - (
_boxSize(icon).width
@@ -851,144 +841,72 @@
+ _boxSize(suffix).width
+ _boxSize(suffixIcon).width
+ contentPadding.right));
- boxToBaseline[label] = _layoutLineBox(
- label,
- boxConstraints.copyWith(maxWidth: inputWidth),
- );
- boxToBaseline[hint] = _layoutLineBox(
- hint,
- boxConstraints.copyWith(minWidth: inputWidth, maxWidth: inputWidth),
- );
- boxToBaseline[counter] = _layoutLineBox(counter, boxConstraints);
- // The helper or error text can occupy the full width less the space
- // occupied by the icon and counter.
- boxToBaseline[helperError] = _layoutLineBox(
- helperError,
- boxConstraints.copyWith(
+ boxConstraints = boxConstraints.copyWith(maxWidth: inputWidth);
+ if (label != null) {
+ if (decoration.alignLabelWithHint) {
+ // The label is aligned with the hint, at the baseline
+ layoutLineBox(label);
+ } else {
+ // The label is centered, not baseline aligned
+ label.layout(boxConstraints, parentUsesSize: true);
+ }
+ }
+
+ boxConstraints = boxConstraints.copyWith(minWidth: inputWidth);
+ layoutLineBox(hint);
+ layoutLineBox(input);
+
+ double inputBaseline = contentPadding.top + aboveBaseline;
+ double containerHeight = contentPadding.top
+ + aboveBaseline
+ + belowBaseline
+ + contentPadding.bottom;
+
+ if (label != null) {
+ // floatingLabelHeight includes the vertical gap between the inline
+ // elements and the floating label.
+ containerHeight += decoration.floatingLabelHeight;
+ 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.
+ final double outlineBaseline = aboveBaseline +
+ (containerHeight - (2.0 + aboveBaseline + belowBaseline)) / 2.0;
+
+ double subtextBaseline = 0.0;
+ double subtextHeight = 0.0;
+ if (helperError != null || counter != null) {
+ boxConstraints = layoutConstraints.loosen();
+ aboveBaseline = 0.0;
+ belowBaseline = 0.0;
+ layoutLineBox(counter);
+
+ // The helper or error text can occupy the full width less the space
+ // occupied by the icon and counter.
+ boxConstraints = boxConstraints.copyWith(
maxWidth: math.max(0.0, boxConstraints.maxWidth
- _boxSize(icon).width
- _boxSize(counter).width
- contentPadding.horizontal,
),
- ),
- );
+ );
+ layoutLineBox(helperError);
- // The height of the input needs to accommodate label above and counter and
- // helperError below, when they exist.
- const double subtextGap = 8.0;
- final double labelHeight = label == null
- ? 0
- : decoration.floatingLabelHeight;
- final double topHeight = decoration.border.isOutline
- ? math.max(labelHeight - boxToBaseline[label], 0)
- : labelHeight;
- final double counterHeight = counter == null
- ? 0
- : boxToBaseline[counter] + subtextGap * 2;
- final _HelperError helperErrorWidget = decoration.helperError;
- final double helperErrorHeight = helperErrorWidget.helperText == null
- ? 0
- : helperError.size.height + subtextGap * 2;
- final double bottomHeight = math.max(
- counterHeight,
- helperErrorHeight,
- );
- boxToBaseline[input] = _layoutLineBox(
- input,
- boxConstraints.deflate(EdgeInsets.only(
- top: contentPadding.top + topHeight,
- bottom: contentPadding.bottom + bottomHeight,
- )).copyWith(
- minWidth: inputWidth,
- maxWidth: inputWidth,
- ),
- );
-
- // The field can be occupied by a hint or by the input itself
- final double hintHeight = hint == null ? 0 : hint.size.height;
- final double inputDirectHeight = input == null ? 0 : input.size.height;
- final double inputHeight = math.max(hintHeight, inputDirectHeight);
- final double inputInternalBaseline = math.max(
- boxToBaseline[input],
- boxToBaseline[hint],
- );
-
- // Calculate the amount that prefix/suffix affects height above and below
- // the input.
- final double prefixHeight = prefix == null ? 0 : prefix.size.height;
- final double suffixHeight = suffix == null ? 0 : suffix.size.height;
- final double fixHeight = math.max(
- boxToBaseline[prefix],
- boxToBaseline[suffix],
- );
- final double fixAboveInput = math.max(0, fixHeight - inputInternalBaseline);
- final double fixBelowBaseline = math.max(
- prefixHeight - boxToBaseline[prefix],
- suffixHeight - boxToBaseline[suffix],
- );
- final double fixBelowInput = math.max(
- 0,
- fixBelowBaseline - (inputHeight - inputInternalBaseline),
- );
-
- // Calculate the height of the input text container.
- final double prefixIconHeight = prefixIcon == null ? 0 : prefixIcon.size.height;
- final double suffixIconHeight = suffixIcon == null ? 0 : suffixIcon.size.height;
- final double fixIconHeight = math.max(prefixIconHeight, suffixIconHeight);
- final double contentHeight = math.max(
- fixIconHeight,
- topHeight
- + contentPadding.top
- + fixAboveInput
- + inputHeight
- + fixBelowInput
- + contentPadding.bottom,
- );
- final double maxContainerHeight = boxConstraints.maxHeight - bottomHeight;
- final double containerHeight = expands
- ? maxContainerHeight
- : math.min(contentHeight, maxContainerHeight);
-
- // Always position the prefix/suffix in the same place (baseline).
- final double overflow = math.max(0, contentHeight - maxContainerHeight);
- final double baselineAdjustment = fixAboveInput - overflow;
-
- // The baselines that will be used to draw the actual input text content.
- final double inputBaseline = contentPadding.top
- + topHeight
- + inputInternalBaseline
- + baselineAdjustment;
- // The text in the input when an outline border is present is centered
- // within the container less 2.0 dps at the top to account for the vertical
- // space occupied by the floating label.
- final double outlineBaseline = inputInternalBaseline
- + baselineAdjustment / 2
- + (containerHeight - (2.0 + inputHeight)) / 2.0;
-
- // Find the positions of the text below the input when it exists.
- double subtextCounterBaseline = 0;
- double subtextHelperBaseline = 0;
- double subtextCounterHeight = 0;
- double subtextHelperHeight = 0;
- if (counter != null) {
- subtextCounterBaseline =
- containerHeight + subtextGap + boxToBaseline[counter];
- subtextCounterHeight = counter.size.height + subtextGap;
+ if (aboveBaseline + belowBaseline > 0.0) {
+ const double subtextGap = 8.0;
+ subtextBaseline = containerHeight + subtextGap + aboveBaseline;
+ subtextHeight = subtextGap + aboveBaseline + belowBaseline;
+ }
}
- if (helperErrorWidget.helperText != null) {
- subtextHelperBaseline =
- containerHeight + subtextGap + boxToBaseline[helperError];
- subtextHelperHeight = helperError.size.height + subtextGap;
- }
- final double subtextBaseline = math.max(
- subtextCounterBaseline,
- subtextHelperBaseline,
- );
- final double subtextHeight = math.max(
- subtextCounterHeight,
- subtextHelperHeight,
- );
return _RenderDecorationLayout(
boxToBaseline: boxToBaseline,
@@ -1452,18 +1370,15 @@
@required this.textDirection,
@required this.textBaseline,
@required this.isFocused,
- @required this.expands,
}) : assert(decoration != null),
assert(textDirection != null),
assert(textBaseline != null),
- assert(expands != null),
super(key: key);
final _Decoration decoration;
final TextDirection textDirection;
final TextBaseline textBaseline;
final bool isFocused;
- final bool expands;
@override
_RenderDecorationElement createElement() => _RenderDecorationElement(this);
@@ -1475,7 +1390,6 @@
textDirection: textDirection,
textBaseline: textBaseline,
isFocused: isFocused,
- expands: expands,
);
}
@@ -1485,7 +1399,6 @@
..decoration = decoration
..textDirection = textDirection
..textBaseline = textBaseline
- ..expands = expands
..isFocused = isFocused;
}
}
@@ -1548,7 +1461,6 @@
this.baseStyle,
this.textAlign,
this.isFocused = false,
- this.expands = false,
this.isEmpty = false,
this.child,
}) : assert(isFocused != null),
@@ -1583,19 +1495,6 @@
/// Defaults to false.
final bool isFocused;
- /// If true, the height of the input field will be as large as possible.
- ///
- /// If wrapped in a widget that constrains its child's height, like Expanded
- /// or SizedBox, the input field will only be affected if [expands] is set to
- /// true.
- ///
- /// See [TextField.minLines] and [TextField.maxLines] for related ways to
- /// affect the height of an input. When [expands] is true, both must be null
- /// in order to avoid ambiguity in determining the height.
- ///
- /// Defaults to false.
- final bool expands;
-
/// Whether the input field is empty.
///
/// Determines the position of the label text and whether to display the hint
@@ -1634,7 +1533,6 @@
properties.add(DiagnosticsProperty<InputDecoration>('decoration', decoration));
properties.add(DiagnosticsProperty<TextStyle>('baseStyle', baseStyle, defaultValue: null));
properties.add(DiagnosticsProperty<bool>('isFocused', isFocused));
- properties.add(DiagnosticsProperty<bool>('expands', expands, defaultValue: false));
properties.add(DiagnosticsProperty<bool>('isEmpty', isEmpty));
}
}
@@ -2030,7 +1928,6 @@
textDirection: textDirection,
textBaseline: textBaseline,
isFocused: isFocused,
- expands: widget.expands,
);
}
}
diff --git a/packages/flutter/lib/src/material/text_field.dart b/packages/flutter/lib/src/material/text_field.dart
index 6399488..9b8b141 100644
--- a/packages/flutter/lib/src/material/text_field.dart
+++ b/packages/flutter/lib/src/material/text_field.dart
@@ -147,8 +147,6 @@
this.obscureText = false,
this.autocorrect = true,
this.maxLines = 1,
- this.minLines,
- this.expands = false,
this.maxLength,
this.maxLengthEnforced = true,
this.onChanged,
@@ -173,16 +171,6 @@
assert(scrollPadding != null),
assert(dragStartBehavior != null),
assert(maxLines == null || maxLines > 0),
- assert(minLines == null || minLines > 0),
- assert(
- (maxLines == null) || (minLines == null) || (maxLines >= minLines),
- 'minLines can\'t be greater than maxLines',
- ),
- assert(expands != null),
- assert(
- !expands || (maxLines == null && minLines == null),
- 'minLines and maxLines must be null when expands is true.',
- ),
assert(maxLength == null || maxLength == TextField.noMaxLength || maxLength > 0),
keyboardType = keyboardType ?? (maxLines == 1 ? TextInputType.text : TextInputType.multiline),
super(key: key);
@@ -281,12 +269,6 @@
/// {@macro flutter.widgets.editableText.maxLines}
final int maxLines;
- /// {@macro flutter.widgets.editableText.minLines}
- final int minLines;
-
- /// {@macro flutter.widgets.editableText.expands}
- final bool expands;
-
/// If [maxLength] is set to this value, only the "current input length"
/// part of the character counter is shown.
static const int noMaxLength = -1;
@@ -475,8 +457,6 @@
properties.add(DiagnosticsProperty<bool>('obscureText', obscureText, defaultValue: false));
properties.add(DiagnosticsProperty<bool>('autocorrect', autocorrect, defaultValue: true));
properties.add(IntProperty('maxLines', maxLines, defaultValue: 1));
- properties.add(IntProperty('minLines', minLines, defaultValue: null));
- properties.add(DiagnosticsProperty<bool>('expands', expands, defaultValue: false));
properties.add(IntProperty('maxLength', maxLength, defaultValue: null));
properties.add(FlagProperty('maxLengthEnforced', value: maxLengthEnforced, defaultValue: true, ifFalse: 'maxLength not enforced'));
properties.add(EnumProperty<TextInputAction>('textInputAction', textInputAction, defaultValue: null));
@@ -871,8 +851,6 @@
obscureText: widget.obscureText,
autocorrect: widget.autocorrect,
maxLines: widget.maxLines,
- minLines: widget.minLines,
- expands: widget.expands,
selectionColor: themeData.textSelectionColor,
selectionControls: widget.selectionEnabled ? textSelectionControls : null,
onChanged: widget.onChanged,
@@ -905,7 +883,6 @@
textAlign: widget.textAlign,
isFocused: focusNode.hasFocus,
isEmpty: controller.value.text.isEmpty,
- expands: widget.expands,
child: child,
);
},
diff --git a/packages/flutter/lib/src/rendering/box.dart b/packages/flutter/lib/src/rendering/box.dart
index 283d734..eb4d494 100644
--- a/packages/flutter/lib/src/rendering/box.dart
+++ b/packages/flutter/lib/src/rendering/box.dart
@@ -1801,9 +1801,9 @@
testIntrinsicsForValues(getMinIntrinsicWidth, getMaxIntrinsicWidth, 'Width', double.infinity);
testIntrinsicsForValues(getMinIntrinsicHeight, getMaxIntrinsicHeight, 'Height', double.infinity);
if (constraints.hasBoundedWidth)
- testIntrinsicsForValues(getMinIntrinsicWidth, getMaxIntrinsicWidth, 'Width', constraints.maxHeight);
+ testIntrinsicsForValues(getMinIntrinsicWidth, getMaxIntrinsicWidth, 'Width', constraints.maxWidth);
if (constraints.hasBoundedHeight)
- testIntrinsicsForValues(getMinIntrinsicHeight, getMaxIntrinsicHeight, 'Height', constraints.maxWidth);
+ testIntrinsicsForValues(getMinIntrinsicHeight, getMaxIntrinsicHeight, 'Height', constraints.maxHeight);
// TODO(ianh): Test that values are internally consistent in more ways than the above.
diff --git a/packages/flutter/lib/src/rendering/editable.dart b/packages/flutter/lib/src/rendering/editable.dart
index 27b5f6b..adbbc63 100644
--- a/packages/flutter/lib/src/rendering/editable.dart
+++ b/packages/flutter/lib/src/rendering/editable.dart
@@ -144,8 +144,6 @@
ValueNotifier<bool> showCursor,
bool hasFocus,
int maxLines = 1,
- int minLines,
- bool expands = false,
StrutStyle strutStyle,
Color selectionColor,
double textScaleFactor = 1.0,
@@ -167,16 +165,6 @@
}) : assert(textAlign != null),
assert(textDirection != null, 'RenderEditable created without a textDirection.'),
assert(maxLines == null || maxLines > 0),
- assert(minLines == null || minLines > 0),
- assert(
- (maxLines == null) || (minLines == null) || (maxLines >= minLines),
- 'minLines can\'t be greater than maxLines',
- ),
- assert(expands != null),
- assert(
- !expands || (maxLines == null && minLines == null),
- 'minLines and maxLines must be null when expands is true.',
- ),
assert(textScaleFactor != null),
assert(offset != null),
assert(ignorePointer != null),
@@ -198,8 +186,6 @@
_showCursor = showCursor ?? ValueNotifier<bool>(false),
_hasFocus = hasFocus ?? false,
_maxLines = maxLines,
- _minLines = minLines,
- _expands = expands,
_selectionColor = selectionColor,
_selection = selection,
_offset = offset,
@@ -705,29 +691,6 @@
markNeedsTextLayout();
}
- /// {@macro flutter.widgets.editableText.minLines}
- int get minLines => _minLines;
- int _minLines;
- /// The value may be null. If it is not null, then it must be greater than zero.
- set minLines(int value) {
- assert(value == null || value > 0);
- if (minLines == value)
- return;
- _minLines = value;
- markNeedsTextLayout();
- }
-
- /// {@macro flutter.widgets.editableText.expands}
- bool get expands => _expands;
- bool _expands;
- set expands(bool value) {
- assert(value != null);
- if (expands == value)
- return;
- _expands = value;
- markNeedsTextLayout();
- }
-
/// The color to use when painting the selection.
Color get selectionColor => _selectionColor;
Color _selectionColor;
@@ -1187,28 +1150,8 @@
double get preferredLineHeight => _textPainter.preferredLineHeight;
double _preferredHeight(double width) {
- // Lock height to maxLines if needed
- final bool lockedMax = maxLines != null && minLines == null;
- final bool lockedBoth = minLines != null && minLines == maxLines;
- final bool singleLine = maxLines == 1;
- if (singleLine || lockedMax || lockedBoth) {
+ if (maxLines != null)
return preferredLineHeight * maxLines;
- }
-
- // Clamp height to minLines or maxLines if needed
- final bool minLimited = minLines != null && minLines > 1;
- final bool maxLimited = maxLines != null;
- if (minLimited || maxLimited) {
- _layoutText(width);
- if (minLimited && _textPainter.height < preferredLineHeight * minLines) {
- return preferredLineHeight * minLines;
- }
- if (maxLimited && _textPainter.height > preferredLineHeight * maxLines) {
- return preferredLineHeight * maxLines;
- }
- }
-
- // Set the height based on the content
if (width == double.infinity) {
final String text = _textPainter.text.toPlainText();
int lines = 1;
@@ -1670,8 +1613,6 @@
properties.add(DiagnosticsProperty<Color>('cursorColor', cursorColor));
properties.add(DiagnosticsProperty<ValueNotifier<bool>>('showCursor', showCursor));
properties.add(IntProperty('maxLines', maxLines));
- properties.add(IntProperty('minLines', minLines));
- properties.add(DiagnosticsProperty<bool>('expands', expands, defaultValue: false));
properties.add(DiagnosticsProperty<Color>('selectionColor', selectionColor));
properties.add(DoubleProperty('textScaleFactor', textScaleFactor));
properties.add(DiagnosticsProperty<Locale>('locale', locale, defaultValue: null));
diff --git a/packages/flutter/lib/src/widgets/editable_text.dart b/packages/flutter/lib/src/widgets/editable_text.dart
index d6a0b04..1012034 100644
--- a/packages/flutter/lib/src/widgets/editable_text.dart
+++ b/packages/flutter/lib/src/widgets/editable_text.dart
@@ -278,8 +278,6 @@
this.locale,
this.textScaleFactor,
this.maxLines = 1,
- this.minLines,
- this.expands = false,
this.autofocus = false,
this.selectionColor,
this.selectionControls,
@@ -312,16 +310,6 @@
assert(backgroundCursorColor != null),
assert(textAlign != null),
assert(maxLines == null || maxLines > 0),
- assert(minLines == null || minLines > 0),
- assert(
- (maxLines == null) || (minLines == null) || (maxLines >= minLines),
- 'minLines can\'t be greater than maxLines',
- ),
- assert(expands != null),
- assert(
- !expands || (maxLines == null && minLines == null),
- 'minLines and maxLines must be null when expands is true.',
- ),
assert(autofocus != null),
assert(rendererIgnoresPointer != null),
assert(scrollPadding != null),
@@ -477,78 +465,12 @@
/// container will start with enough vertical space for one line and
/// automatically grow to accommodate additional lines as they are entered.
///
- /// If this is not null, the value must be greater than zero, and it will lock
- /// the input to the given number of lines and take up enough horizontal space
- /// to accommodate that number of lines. Setting [minLines] as well allows the
- /// input to grow between the indicated range.
- ///
- /// The full set of behaviors possible with [minLines] and [maxLines] are as
- /// follows. These examples apply equally to `TextField`, `TextFormField`, and
- /// `EditableText`.
- ///
- /// Input that occupies a single line and scrolls horizontally as needed.
- /// ```dart
- /// TextField()
- /// ```
- ///
- /// Input whose height grows from one line up to as many lines as needed for
- /// the text that was entered. If a height limit is imposed by its parent, it
- /// will scroll vertically when its height reaches that limit.
- /// ```dart
- /// TextField(maxLines: null)
- /// ```
- ///
- /// The input's height is large enough for the given number of lines. If
- /// additional lines are entered the input scrolls vertically.
- /// ```dart
- /// TextField(maxLines: 2)
- /// ```
- ///
- /// Input whose height grows with content between a min and max. An infinite
- /// max is possible with `maxLines: null`.
- /// ```dart
- /// TextField(minLines: 2, maxLines: 4)
- /// ```
+ /// If it is not null, the value must be greater than zero. If it is greater
+ /// than 1, it will take up enough horizontal space to accommodate that number
+ /// of lines.
/// {@endtemplate}
final int maxLines;
- /// {@template flutter.widgets.editableText.minLines}
- /// The minimum number of lines to occupy when the content spans fewer lines.
-
- /// When [maxLines] is set as well, the height will grow between the indicated
- /// range of lines. When [maxLines] is null, it will grow as high as needed,
- /// starting from [minLines].
- ///
- /// See the examples in [maxLines] for the complete picture of how [maxLines]
- /// and [minLines] interact to produce various behaviors.
- ///
- /// Defaults to null.
- /// {@endtemplate}
- final int minLines;
-
- /// {@template flutter.widgets.editableText.expands}
- /// Whether this widget's height will be sized to fill its parent.
- ///
- /// If set to true and wrapped in a parent widget like [Expanded] or
- /// [SizedBox], the input will expand to fill the parent.
- ///
- /// [maxLines] and [minLines] must both be null when this is set to true,
- /// otherwise an error is thrown.
- ///
- /// Defaults to false.
- ///
- /// See the examples in [maxLines] for the complete picture of how [maxLines],
- /// [minLines], and [expands] interact to produce various behaviors.
- ///
- /// Input that matches the height of its parent
- /// ```dart
- /// Expanded(
- /// child: TextField(maxLines: null, expands: true),
- /// )
- /// ```
- /// {@endtemplate}
- final bool expands;
-
/// {@template flutter.widgets.editableText.autofocus}
/// Whether this text field should focus itself if nothing else is already
/// focused.
@@ -754,8 +676,6 @@
properties.add(DiagnosticsProperty<Locale>('locale', locale, defaultValue: null));
properties.add(DoubleProperty('textScaleFactor', textScaleFactor, defaultValue: null));
properties.add(IntProperty('maxLines', maxLines, defaultValue: 1));
- properties.add(IntProperty('minLines', minLines, defaultValue: null));
- properties.add(DiagnosticsProperty<bool>('expands', expands, defaultValue: false));
properties.add(DiagnosticsProperty<bool>('autofocus', autofocus, defaultValue: false));
properties.add(DiagnosticsProperty<TextInputType>('keyboardType', keyboardType, defaultValue: null));
}
@@ -875,7 +795,7 @@
// If this is a multiline EditableText, do nothing for a "newline"
// action; The newline is already inserted. Otherwise, finalize
// editing.
- if (!_isMultiline)
+ if (widget.maxLines == 1)
_finalizeEditing(true);
break;
case TextInputAction.done:
@@ -1413,8 +1333,6 @@
: _cursorVisibilityNotifier,
hasFocus: _hasFocus,
maxLines: widget.maxLines,
- minLines: widget.minLines,
- expands: widget.expands,
strutStyle: widget.strutStyle,
selectionColor: widget.selectionColor,
textScaleFactor: widget.textScaleFactor ?? MediaQuery.textScaleFactorOf(context),
@@ -1485,8 +1403,6 @@
this.showCursor,
this.hasFocus,
this.maxLines,
- this.minLines,
- this.expands,
this.strutStyle,
this.selectionColor,
this.textScaleFactor,
@@ -1517,8 +1433,6 @@
final ValueNotifier<bool> showCursor;
final bool hasFocus;
final int maxLines;
- final int minLines;
- final bool expands;
final StrutStyle strutStyle;
final Color selectionColor;
final double textScaleFactor;
@@ -1548,8 +1462,6 @@
showCursor: showCursor,
hasFocus: hasFocus,
maxLines: maxLines,
- minLines: minLines,
- expands: expands,
strutStyle: strutStyle,
selectionColor: selectionColor,
textScaleFactor: textScaleFactor,
@@ -1580,8 +1492,6 @@
..showCursor = showCursor
..hasFocus = hasFocus
..maxLines = maxLines
- ..minLines = minLines
- ..expands = expands
..strutStyle = strutStyle
..selectionColor = selectionColor
..textScaleFactor = textScaleFactor
diff --git a/packages/flutter/test/material/input_decorator_test.dart b/packages/flutter/test/material/input_decorator_test.dart
index 8e8cba8..101a1eb 100644
--- a/packages/flutter/test/material/input_decorator_test.dart
+++ b/packages/flutter/test/material/input_decorator_test.dart
@@ -993,100 +993,6 @@
expect(tester.getTopRight(find.text('text')).dx, lessThanOrEqualTo(tester.getTopRight(find.byKey(sKey)).dx));
});
- testWidgets('InputDecorator tall prefix', (WidgetTester tester) async {
- const Key pKey = Key('p');
- await tester.pumpWidget(
- buildInputDecorator(
- // isEmpty: false (default)
- // isFocused: false (default)
- decoration: InputDecoration(
- prefix: Container(
- key: pKey,
- height: 100,
- width: 10,
- ),
- filled: true,
- ),
- // Set the fontSize so that everything works out to whole numbers.
- child: const Text(
- 'text',
- style: TextStyle(fontFamily: 'Ahem', fontSize: 20.0),
- ),
- ),
- );
-
- // Overall height for this InputDecorator is ~127.2dps because
- // the prefix is 100dps tall, but it aligns with the input's baseline,
- // overlapping the input a bit.
- // 12 - top padding
- // 100 - total height of prefix
- // -16 - input prefix overlap (distance input top to baseline, not exact)
- // 20 - input text (ahem font size 16dps)
- // 0 - bottom prefix/suffix padding
- // 12 - bottom padding
-
- expect(tester.getSize(find.byType(InputDecorator)).width, 800.0);
- expect(tester.getSize(find.byType(InputDecorator)).height, closeTo(128.0, .0001));
- expect(tester.getSize(find.text('text')).height, 20.0);
- expect(tester.getSize(find.byKey(pKey)).height, 100.0);
- expect(tester.getTopLeft(find.text('text')).dy, closeTo(96, .0001)); // 12 + 100 - 16
- expect(tester.getTopLeft(find.byKey(pKey)).dy, 12.0);
-
- // layout is a row: [prefix text suffix]
- expect(tester.getTopLeft(find.byKey(pKey)).dx, 12.0);
- expect(tester.getTopRight(find.byKey(pKey)).dx, tester.getTopLeft(find.text('text')).dx);
- });
-
- testWidgets('InputDecorator tall prefix with border', (WidgetTester tester) async {
- const Key pKey = Key('p');
- await tester.pumpWidget(
- buildInputDecorator(
- // isEmpty: false (default)
- // isFocused: false (default)
- decoration: InputDecoration(
- border: const OutlineInputBorder(),
- prefix: Container(
- key: pKey,
- height: 100,
- width: 10,
- ),
- filled: true,
- ),
- // Set the fontSize so that everything works out to whole numbers.
- child: const Text(
- 'text',
- style: TextStyle(fontFamily: 'Ahem', fontSize: 20.0),
- ),
- ),
- );
-
- // Overall height for this InputDecorator is ~127.2dps because
- // the prefix is 100dps tall, but it aligns with the input's baseline,
- // overlapping the input a bit.
- // 24 - top padding
- // 100 - total height of prefix
- // -16 - input prefix overlap (distance input top to baseline, not exact)
- // 20 - input text (ahem font size 16dps)
- // 0 - bottom prefix/suffix padding
- // 16 - bottom padding
- // When a border is present, the input text and prefix/suffix are centered
- // within the input. Here, that will be content of height 106, including 2
- // extra pixels of space, centered within an input of height 144. That gives
- // 19 pixels of space on each side of the content, so the prefix is
- // positioned at 19, and the text is at 19+100-16=103.
-
- expect(tester.getSize(find.byType(InputDecorator)).width, 800.0);
- expect(tester.getSize(find.byType(InputDecorator)).height, closeTo(144, .0001));
- expect(tester.getSize(find.text('text')).height, 20.0);
- expect(tester.getSize(find.byKey(pKey)).height, 100.0);
- expect(tester.getTopLeft(find.text('text')).dy, closeTo(103, .0001));
- expect(tester.getTopLeft(find.byKey(pKey)).dy, 19.0);
-
- // layout is a row: [prefix text suffix]
- expect(tester.getTopLeft(find.byKey(pKey)).dx, 12.0);
- expect(tester.getTopRight(find.byKey(pKey)).dx, tester.getTopLeft(find.text('text')).dx);
- });
-
testWidgets('InputDecorator prefixIcon/suffixIcon', (WidgetTester tester) async {
await tester.pumpWidget(
buildInputDecorator(
@@ -1169,6 +1075,7 @@
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(
@@ -1556,12 +1463,12 @@
testWidgets('InputDecoration outline shape with no border and no floating placeholder', (WidgetTester tester) async {
await tester.pumpWidget(
buildInputDecorator(
- // isFocused: false (default)
- isEmpty: true,
- decoration: const InputDecoration(
- border: OutlineInputBorder(borderSide: BorderSide.none),
- hasFloatingPlaceholder: false,
- labelText: 'label',
+ // isFocused: false (default)
+ isEmpty: true,
+ decoration: const InputDecoration(
+ border: OutlineInputBorder(borderSide: BorderSide.none),
+ hasFloatingPlaceholder: false,
+ labelText: 'label',
),
),
);
diff --git a/packages/flutter/test/material/text_field_focus_test.dart b/packages/flutter/test/material/text_field_focus_test.dart
index f7044ee..67039ea 100644
--- a/packages/flutter/test/material/text_field_focus_test.dart
+++ b/packages/flutter/test/material/text_field_focus_test.dart
@@ -6,49 +6,6 @@
import 'package:flutter/material.dart';
void main() {
- testWidgets('Dialog interaction', (WidgetTester tester) async {
- expect(tester.testTextInput.isVisible, isFalse);
-
- await tester.pumpWidget(
- const MaterialApp(
- home: Material(
- child: Center(
- child: TextField(
- autofocus: true,
- ),
- ),
- ),
- ),
- );
-
- expect(tester.testTextInput.isVisible, isTrue);
-
- final BuildContext context = tester.element(find.byType(TextField));
-
- showDialog<void>(
- context: context,
- builder: (BuildContext context) => const SimpleDialog(title: Text('Dialog')),
- );
-
- await tester.pump();
-
- expect(tester.testTextInput.isVisible, isFalse);
-
- Navigator.of(tester.element(find.text('Dialog'))).pop();
- await tester.pump();
-
- expect(tester.testTextInput.isVisible, isFalse);
-
- await tester.tap(find.byType(TextField));
- await tester.idle();
-
- expect(tester.testTextInput.isVisible, isTrue);
-
- await tester.pumpWidget(Container());
-
- expect(tester.testTextInput.isVisible, isFalse);
- });
-
testWidgets('Request focus shows keyboard', (WidgetTester tester) async {
final FocusNode focusNode = FocusNode();
@@ -132,6 +89,49 @@
expect(tester.testTextInput.isVisible, isFalse);
});
+ testWidgets('Dialog interaction', (WidgetTester tester) async {
+ expect(tester.testTextInput.isVisible, isFalse);
+
+ await tester.pumpWidget(
+ const MaterialApp(
+ home: Material(
+ child: Center(
+ child: TextField(
+ autofocus: true,
+ ),
+ ),
+ ),
+ ),
+ );
+
+ expect(tester.testTextInput.isVisible, isTrue);
+
+ final BuildContext context = tester.element(find.byType(TextField));
+
+ showDialog<void>(
+ context: context,
+ builder: (BuildContext context) => const SimpleDialog(title: Text('Dialog')),
+ );
+
+ await tester.pump();
+
+ expect(tester.testTextInput.isVisible, isFalse);
+
+ Navigator.of(tester.element(find.text('Dialog'))).pop();
+ await tester.pump();
+
+ expect(tester.testTextInput.isVisible, isFalse);
+
+ await tester.tap(find.byType(TextField));
+ await tester.idle();
+
+ expect(tester.testTextInput.isVisible, isTrue);
+
+ await tester.pumpWidget(Container());
+
+ expect(tester.testTextInput.isVisible, isFalse);
+ });
+
testWidgets('Focus triggers keep-alive', (WidgetTester tester) async {
final FocusNode focusNode = FocusNode();
diff --git a/packages/flutter/test/material/text_field_test.dart b/packages/flutter/test/material/text_field_test.dart
index 20dadfc..7cd6d3b 100644
--- a/packages/flutter/test/material/text_field_test.dart
+++ b/packages/flutter/test/material/text_field_test.dart
@@ -174,24 +174,6 @@
debugResetSemanticsIdCounter();
});
- final Key textFieldKey = UniqueKey();
- Widget textFieldBuilder({
- int maxLines = 1,
- int minLines,
- }) {
- return boilerplate(
- child: TextField(
- key: textFieldKey,
- style: const TextStyle(color: Colors.black, fontSize: 34.0),
- maxLines: maxLines,
- minLines: minLines,
- decoration: const InputDecoration(
- hintText: 'Placeholder',
- ),
- ),
- );
- }
-
testWidgets('TextField passes onEditingComplete to EditableText', (WidgetTester tester) async {
final VoidCallback onEditingComplete = () { };
@@ -901,288 +883,71 @@
expect(controller.selection.isCollapsed, false);
});
- testWidgets('TextField height with minLines unset', (WidgetTester tester) async {
- await tester.pumpWidget(textFieldBuilder());
+ testWidgets('Multiline text will wrap up to maxLines', (WidgetTester tester) async {
+ final Key textFieldKey = UniqueKey();
- RenderBox findInputBox() => tester.renderObject(find.byKey(textFieldKey));
-
- final RenderBox inputBox = findInputBox();
- final Size emptyInputSize = inputBox.size;
-
- await tester.enterText(find.byType(TextField), 'No wrapping here.');
- await tester.pumpWidget(textFieldBuilder());
- expect(findInputBox(), equals(inputBox));
- expect(inputBox.size, equals(emptyInputSize));
-
- // Even when entering multiline text, TextField doesn't grow. It's a single
- // line input.
- await tester.enterText(find.byType(TextField), kThreeLines);
- await tester.pumpWidget(textFieldBuilder());
- expect(findInputBox(), equals(inputBox));
- expect(inputBox.size, equals(emptyInputSize));
-
- // maxLines: 3 makes the TextField 3 lines tall
- await tester.enterText(find.byType(TextField), '');
- await tester.pumpWidget(textFieldBuilder(maxLines: 3));
- expect(findInputBox(), equals(inputBox));
- expect(inputBox.size.height, greaterThan(emptyInputSize.height));
- expect(inputBox.size.width, emptyInputSize.width);
-
- final Size threeLineInputSize = inputBox.size;
-
- // Filling with 3 lines of text stays the same size
- await tester.enterText(find.byType(TextField), kThreeLines);
- await tester.pumpWidget(textFieldBuilder(maxLines: 3));
- expect(findInputBox(), equals(inputBox));
- expect(inputBox.size, threeLineInputSize);
-
- // An extra line won't increase the size because we max at 3.
- await tester.enterText(find.byType(TextField), kMoreThanFourLines);
- await tester.pumpWidget(textFieldBuilder(maxLines: 3));
- expect(findInputBox(), equals(inputBox));
- expect(inputBox.size, threeLineInputSize);
-
- // But now it will... but it will max at four
- await tester.enterText(find.byType(TextField), kMoreThanFourLines);
- await tester.pumpWidget(textFieldBuilder(maxLines: 4));
- expect(findInputBox(), equals(inputBox));
- expect(inputBox.size.height, greaterThan(threeLineInputSize.height));
- expect(inputBox.size.width, threeLineInputSize.width);
-
- final Size fourLineInputSize = inputBox.size;
-
- // Now it won't max out until the end
- await tester.enterText(find.byType(TextField), '');
- await tester.pumpWidget(textFieldBuilder(maxLines: null));
- expect(findInputBox(), equals(inputBox));
- expect(inputBox.size, equals(emptyInputSize));
- await tester.enterText(find.byType(TextField), kThreeLines);
- await tester.pump();
- expect(inputBox.size, equals(threeLineInputSize));
- await tester.enterText(find.byType(TextField), kMoreThanFourLines);
- await tester.pump();
- expect(inputBox.size.height, greaterThan(fourLineInputSize.height));
- expect(inputBox.size.width, fourLineInputSize.width);
- });
-
- testWidgets('TextField height with minLines and maxLines', (WidgetTester tester) async {
- await tester.pumpWidget(textFieldBuilder());
-
- RenderBox findInputBox() => tester.renderObject(find.byKey(textFieldKey));
-
- final RenderBox inputBox = findInputBox();
- final Size emptyInputSize = inputBox.size;
-
- await tester.enterText(find.byType(TextField), 'No wrapping here.');
- await tester.pumpWidget(textFieldBuilder());
- expect(findInputBox(), equals(inputBox));
- expect(inputBox.size, equals(emptyInputSize));
-
- // min and max set to same value locks height to value.
- await tester.pumpWidget(textFieldBuilder(minLines: 3, maxLines: 3));
- expect(findInputBox(), equals(inputBox));
- expect(inputBox.size.height, greaterThan(emptyInputSize.height));
- expect(inputBox.size.width, emptyInputSize.width);
-
- final Size threeLineInputSize = inputBox.size;
-
- // maxLines: null with minLines set grows beyond minLines
- await tester.pumpWidget(textFieldBuilder(minLines: 3, maxLines: null));
- expect(findInputBox(), equals(inputBox));
- expect(inputBox.size, threeLineInputSize);
- await tester.enterText(find.byType(TextField), kMoreThanFourLines);
- await tester.pump();
- expect(inputBox.size.height, greaterThan(threeLineInputSize.height));
- expect(inputBox.size.width, threeLineInputSize.width);
-
- // With minLines and maxLines set, input will expand through the range
- await tester.enterText(find.byType(TextField), '');
- await tester.pumpWidget(textFieldBuilder(minLines: 3, maxLines: 4));
- expect(findInputBox(), equals(inputBox));
- expect(inputBox.size, equals(threeLineInputSize));
- await tester.enterText(find.byType(TextField), kMoreThanFourLines);
- await tester.pump();
- expect(inputBox.size.height, greaterThan(threeLineInputSize.height));
- expect(inputBox.size.width, threeLineInputSize.width);
-
- // minLines can't be greater than maxLines.
- expect(() async {
- await tester.pumpWidget(textFieldBuilder(minLines: 3, maxLines: 2));
- }, throwsAssertionError);
- expect(() async {
- await tester.pumpWidget(textFieldBuilder(minLines: 3));
- }, throwsAssertionError);
-
- // maxLines defaults to 1 and can't be less than minLines
- expect(() async {
- await tester.pumpWidget(textFieldBuilder(minLines: 3));
- }, throwsAssertionError);
- });
-
- testWidgets('Multiline text when wrapped in Expanded', (WidgetTester tester) async {
- Widget expandedTextFieldBuilder({
- int maxLines = 1,
- int minLines,
- bool expands = false,
- }) {
+ Widget builder(int maxLines) {
return boilerplate(
- child: Column(
- mainAxisAlignment: MainAxisAlignment.center,
- children: <Widget>[
- Expanded(
- child: TextField(
- key: textFieldKey,
- style: const TextStyle(color: Colors.black, fontSize: 34.0),
- maxLines: maxLines,
- minLines: minLines,
- expands: expands,
- decoration: const InputDecoration(
- hintText: 'Placeholder',
- ),
- ),
- ),
- ],
- ),
- );
- }
-
- await tester.pumpWidget(expandedTextFieldBuilder());
-
- RenderBox findBorder() {
- return tester.renderObject(find.descendant(
- of: find.byType(InputDecorator),
- matching: find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_BorderContainer'),
- ));
- }
- final RenderBox border = findBorder();
-
- // Without expanded: true and maxLines: null, the TextField does not expand
- // to fill its parent when wrapped in an Expanded widget.
- final Size unexpandedInputSize = border.size;
-
- // It does expand to fill its parent when expands: true, maxLines: null, and
- // it's wrapped in an Expanded widget.
- await tester.pumpWidget(expandedTextFieldBuilder(expands: true, maxLines: null));
- expect(border.size.height, greaterThan(unexpandedInputSize.height));
- expect(border.size.width, unexpandedInputSize.width);
-
- // min/maxLines that is not null and expands: true contradict each other.
- expect(() async {
- await tester.pumpWidget(expandedTextFieldBuilder(expands: true, maxLines: 4));
- }, throwsAssertionError);
- expect(() async {
- await tester.pumpWidget(expandedTextFieldBuilder(expands: true, minLines: 1, maxLines: null));
- }, throwsAssertionError);
- });
-
- testWidgets('Growable TextField when content height exceeds parent', (WidgetTester tester) async {
- const double height = 200.0;
- const double padding = 24.0;
-
- Widget containedTextFieldBuilder({
- Widget counter,
- String helperText,
- String labelText,
- Widget prefix,
- }) {
- return boilerplate(
- child: Container(
- height: height,
- child: TextField(
- key: textFieldKey,
- maxLines: null,
- decoration: InputDecoration(
- counter: counter,
- helperText: helperText,
- labelText: labelText,
- prefix: prefix,
- ),
+ child: TextField(
+ key: textFieldKey,
+ style: const TextStyle(color: Colors.black, fontSize: 34.0),
+ maxLines: maxLines,
+ decoration: const InputDecoration(
+ hintText: 'Placeholder',
),
),
);
}
- await tester.pumpWidget(containedTextFieldBuilder());
- RenderBox findEditableText() => tester.renderObject(find.byType(EditableText));
+ await tester.pumpWidget(builder(null));
- final RenderBox inputBox = findEditableText();
+ RenderBox findInputBox() => tester.renderObject(find.byKey(textFieldKey));
- // With no decoration and when overflowing with content, the EditableText
- // takes up the full height minus the padding, so the input fits perfectly
- // inside the parent.
- await tester.enterText(find.byType(TextField), 'a\n' * 11);
- await tester.pump();
- expect(findEditableText(), equals(inputBox));
- expect(inputBox.size.height, height - padding);
+ final RenderBox inputBox = findInputBox();
+ final Size emptyInputSize = inputBox.size;
- // Adding a counter causes the EditableText to shrink to fit the counter
- // inside the parent as well.
- const double counterHeight = 40.0;
- const double subtextGap = 8.0 * 2;
- const double counterSpace = counterHeight + subtextGap;
- await tester.pumpWidget(containedTextFieldBuilder(
- counter: Container(height: counterHeight),
- ));
- expect(findEditableText(), equals(inputBox));
- expect(inputBox.size.height, height - padding - counterSpace);
+ await tester.enterText(find.byType(TextField), 'No wrapping here.');
+ await tester.pumpWidget(builder(null));
+ expect(findInputBox(), equals(inputBox));
+ expect(inputBox.size, equals(emptyInputSize));
- // Including helperText causes the EditableText to shrink to fit the text
- // inside the parent as well.
- await tester.pumpWidget(containedTextFieldBuilder(
- helperText: 'I am helperText',
- ));
- expect(findEditableText(), equals(inputBox));
- const double helperTextSpace = 28.0;
- expect(inputBox.size.height, height - padding - helperTextSpace);
+ await tester.pumpWidget(builder(3));
+ expect(findInputBox(), equals(inputBox));
+ expect(inputBox.size, greaterThan(emptyInputSize));
- // When both helperText and counter are present, EditableText shrinks by the
- // height of the taller of the two in order to fit both within the parent.
- await tester.pumpWidget(containedTextFieldBuilder(
- counter: Container(height: counterHeight),
- helperText: 'I am helperText',
- ));
- expect(findEditableText(), equals(inputBox));
- expect(inputBox.size.height, height - padding - counterSpace);
+ final Size threeLineInputSize = inputBox.size;
- // When a label is present, EditableText shrinks to fit it at the top so
- // that the bottom of the input still lines up perfectly with the parent.
- await tester.pumpWidget(containedTextFieldBuilder(
- labelText: 'I am labelText',
- ));
- const double labelSpace = 16.0;
- expect(findEditableText(), equals(inputBox));
- expect(inputBox.size.height, height - padding - labelSpace);
+ await tester.enterText(find.byType(TextField), kThreeLines);
+ await tester.pumpWidget(builder(null));
+ expect(findInputBox(), equals(inputBox));
+ expect(inputBox.size, greaterThan(emptyInputSize));
- // When decoration is present on the top and bottom, EditableText shrinks to
- // fit both inside the parent independently.
- await tester.pumpWidget(containedTextFieldBuilder(
- counter: Container(height: counterHeight),
- labelText: 'I am labelText',
- ));
- expect(findEditableText(), equals(inputBox));
- expect(inputBox.size.height, height - padding - counterSpace - labelSpace);
+ await tester.enterText(find.byType(TextField), kThreeLines);
+ await tester.pumpWidget(builder(null));
+ expect(findInputBox(), equals(inputBox));
+ expect(inputBox.size, threeLineInputSize);
- // When a prefix or suffix is present in an input that's full of content,
- // it is ignored and allowed to expand beyond the top of the input. Other
- // top and bottom decoration is still respected.
- await tester.pumpWidget(containedTextFieldBuilder(
- counter: Container(height: counterHeight),
- labelText: 'I am labelText',
- prefix: Container(
- width: 10,
- height: 60,
- ),
- ));
- expect(findEditableText(), equals(inputBox));
- expect(
- inputBox.size.height,
- height
- - padding
- - labelSpace
- - counterSpace,
- );
+ // An extra line won't increase the size because we max at 3.
+ await tester.enterText(find.byType(TextField), kMoreThanFourLines);
+ await tester.pumpWidget(builder(3));
+ expect(findInputBox(), equals(inputBox));
+ expect(inputBox.size, threeLineInputSize);
+
+ // But now it will... but it will max at four
+ await tester.enterText(find.byType(TextField), kMoreThanFourLines);
+ await tester.pumpWidget(builder(4));
+ expect(findInputBox(), equals(inputBox));
+ expect(inputBox.size, greaterThan(threeLineInputSize));
+
+ final Size fourLineInputSize = inputBox.size;
+
+ // Now it won't max out until the end
+ await tester.pumpWidget(builder(null));
+ expect(findInputBox(), equals(inputBox));
+ expect(inputBox.size, greaterThan(fourLineInputSize));
});
+
testWidgets('Multiline hint text will wrap up to maxLines', (WidgetTester tester) async {
final Key textFieldKey = UniqueKey();
diff --git a/packages/flutter/test/rendering/editable_test.dart b/packages/flutter/test/rendering/editable_test.dart
index f54ba7a..196eb31 100644
--- a/packages/flutter/test/rendering/editable_test.dart
+++ b/packages/flutter/test/rendering/editable_test.dart
@@ -56,7 +56,6 @@
' │ cursorColor: null\n'
' │ showCursor: ValueNotifier<bool>#00000(false)\n'
' │ maxLines: 1\n'
- ' │ minLines: null\n'
' │ selectionColor: null\n'
' │ textScaleFactor: 1.0\n'
' │ locale: ja_JP\n'