From f21497ee8c158a2d311a247ea5285ff4f052f52f Mon Sep 17 00:00:00 2001 From: Todd Volkert Date: Sat, 9 Mar 2019 01:17:58 -0800 Subject: [PATCH] Revert "Fix TextField height issues (#27205)" (#29093) This reverts commit 9e9f48dabb8423a6285bddfb21e69f0751060459. --- .../lib/src/material/input_decorator.dart | 271 +++++--------- .../flutter/lib/src/material/text_field.dart | 23 -- packages/flutter/lib/src/rendering/box.dart | 4 +- .../flutter/lib/src/rendering/editable.dart | 61 +--- .../lib/src/widgets/editable_text.dart | 98 +----- .../test/material/input_decorator_test.dart | 107 +----- .../test/material/text_field_focus_test.dart | 86 ++--- .../test/material/text_field_test.dart | 331 +++--------------- .../flutter/test/rendering/editable_test.dart | 1 - 9 files changed, 189 insertions(+), 793 deletions(-) diff --git a/packages/flutter/lib/src/material/input_decorator.dart b/packages/flutter/lib/src/material/input_decorator.dart index 83f1e12d63..ca11f11a86 100644 --- a/packages/flutter/lib/src/material/input_decorator.dart +++ b/packages/flutter/lib/src/material/input_decorator.dart @@ -552,16 +552,13 @@ class _RenderDecoration extends RenderBox { @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 childToSlot = {}; @@ -712,16 +709,6 @@ class _RenderDecoration extends RenderBox { 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 @@ class _RenderDecoration extends RenderBox { 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 boxToBaseline = {}; - 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 @@ class _RenderDecoration extends RenderBox { + _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 @@ class _Decorator extends RenderObjectWidget { @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 @@ class _Decorator extends RenderObjectWidget { textDirection: textDirection, textBaseline: textBaseline, isFocused: isFocused, - expands: expands, ); } @@ -1485,7 +1399,6 @@ class _Decorator extends RenderObjectWidget { ..decoration = decoration ..textDirection = textDirection ..textBaseline = textBaseline - ..expands = expands ..isFocused = isFocused; } } @@ -1548,7 +1461,6 @@ class InputDecorator extends StatefulWidget { this.baseStyle, this.textAlign, this.isFocused = false, - this.expands = false, this.isEmpty = false, this.child, }) : assert(isFocused != null), @@ -1583,19 +1495,6 @@ class InputDecorator extends StatefulWidget { /// 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 @@ class InputDecorator extends StatefulWidget { properties.add(DiagnosticsProperty('decoration', decoration)); properties.add(DiagnosticsProperty('baseStyle', baseStyle, defaultValue: null)); properties.add(DiagnosticsProperty('isFocused', isFocused)); - properties.add(DiagnosticsProperty('expands', expands, defaultValue: false)); properties.add(DiagnosticsProperty('isEmpty', isEmpty)); } } @@ -2030,7 +1928,6 @@ class _InputDecoratorState extends State with TickerProviderStat 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 639948884c..9b8b141e9d 100644 --- a/packages/flutter/lib/src/material/text_field.dart +++ b/packages/flutter/lib/src/material/text_field.dart @@ -147,8 +147,6 @@ class TextField extends StatefulWidget { 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 @@ class TextField extends StatefulWidget { 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 @@ class TextField extends StatefulWidget { /// {@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 @@ class TextField extends StatefulWidget { properties.add(DiagnosticsProperty('obscureText', obscureText, defaultValue: false)); properties.add(DiagnosticsProperty('autocorrect', autocorrect, defaultValue: true)); properties.add(IntProperty('maxLines', maxLines, defaultValue: 1)); - properties.add(IntProperty('minLines', minLines, defaultValue: null)); - properties.add(DiagnosticsProperty('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, defaultValue: null)); @@ -871,8 +851,6 @@ class _TextFieldState extends State with AutomaticKeepAliveClientMixi 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 @@ class _TextFieldState extends State with AutomaticKeepAliveClientMixi 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 283d734b9b..eb4d494c1d 100644 --- a/packages/flutter/lib/src/rendering/box.dart +++ b/packages/flutter/lib/src/rendering/box.dart @@ -1801,9 +1801,9 @@ abstract class RenderBox extends RenderObject { 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 27b5f6b9d2..adbbc63f79 100644 --- a/packages/flutter/lib/src/rendering/editable.dart +++ b/packages/flutter/lib/src/rendering/editable.dart @@ -144,8 +144,6 @@ class RenderEditable extends RenderBox { ValueNotifier showCursor, bool hasFocus, int maxLines = 1, - int minLines, - bool expands = false, StrutStyle strutStyle, Color selectionColor, double textScaleFactor = 1.0, @@ -167,16 +165,6 @@ class RenderEditable extends RenderBox { }) : 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 @@ class RenderEditable extends RenderBox { _showCursor = showCursor ?? ValueNotifier(false), _hasFocus = hasFocus ?? false, _maxLines = maxLines, - _minLines = minLines, - _expands = expands, _selectionColor = selectionColor, _selection = selection, _offset = offset, @@ -705,29 +691,6 @@ class RenderEditable extends RenderBox { 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 @@ class RenderEditable extends RenderBox { 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 @@ class RenderEditable extends RenderBox { properties.add(DiagnosticsProperty('cursorColor', cursorColor)); properties.add(DiagnosticsProperty>('showCursor', showCursor)); properties.add(IntProperty('maxLines', maxLines)); - properties.add(IntProperty('minLines', minLines)); - properties.add(DiagnosticsProperty('expands', expands, defaultValue: false)); properties.add(DiagnosticsProperty('selectionColor', selectionColor)); properties.add(DoubleProperty('textScaleFactor', textScaleFactor)); properties.add(DiagnosticsProperty('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 d6a0b049ed..1012034c32 100644 --- a/packages/flutter/lib/src/widgets/editable_text.dart +++ b/packages/flutter/lib/src/widgets/editable_text.dart @@ -278,8 +278,6 @@ class EditableText extends StatefulWidget { this.locale, this.textScaleFactor, this.maxLines = 1, - this.minLines, - this.expands = false, this.autofocus = false, this.selectionColor, this.selectionControls, @@ -312,16 +310,6 @@ class EditableText extends StatefulWidget { 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 @@ class EditableText extends StatefulWidget { /// 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 @@ class EditableText extends StatefulWidget { properties.add(DiagnosticsProperty('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('expands', expands, defaultValue: false)); properties.add(DiagnosticsProperty('autofocus', autofocus, defaultValue: false)); properties.add(DiagnosticsProperty('keyboardType', keyboardType, defaultValue: null)); } @@ -875,7 +795,7 @@ class EditableTextState extends State with AutomaticKeepAliveClien // 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 @@ class EditableTextState extends State with AutomaticKeepAliveClien : _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 @@ class _Editable extends LeafRenderObjectWidget { this.showCursor, this.hasFocus, this.maxLines, - this.minLines, - this.expands, this.strutStyle, this.selectionColor, this.textScaleFactor, @@ -1517,8 +1433,6 @@ class _Editable extends LeafRenderObjectWidget { final ValueNotifier 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 @@ class _Editable extends LeafRenderObjectWidget { showCursor: showCursor, hasFocus: hasFocus, maxLines: maxLines, - minLines: minLines, - expands: expands, strutStyle: strutStyle, selectionColor: selectionColor, textScaleFactor: textScaleFactor, @@ -1580,8 +1492,6 @@ class _Editable extends LeafRenderObjectWidget { ..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 8e8cba8940..101a1eb459 100644 --- a/packages/flutter/test/material/input_decorator_test.dart +++ b/packages/flutter/test/material/input_decorator_test.dart @@ -993,100 +993,6 @@ void main() { 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 @@ void main() { 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 @@ void main() { 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 f7044ee364..67039eaf69 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_test/flutter_test.dart'; 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( - 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 @@ void main() { 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( + 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 20dadfc3e1..7cd6d3b556 100644 --- a/packages/flutter/test/material/text_field_test.dart +++ b/packages/flutter/test/material/text_field_test.dart @@ -174,24 +174,6 @@ void main() { 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 @@ void main() { 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: [ - 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 f54ba7a35c..196eb317bf 100644 --- a/packages/flutter/test/rendering/editable_test.dart +++ b/packages/flutter/test/rendering/editable_test.dart @@ -56,7 +56,6 @@ void main() { ' │ cursorColor: null\n' ' │ showCursor: ValueNotifier#00000(false)\n' ' │ maxLines: 1\n' - ' │ minLines: null\n' ' │ selectionColor: null\n' ' │ textScaleFactor: 1.0\n' ' │ locale: ja_JP\n'