Commit 0ddcd70c authored by Romain Rastel's avatar Romain Rastel Committed by Justin McCandless

Add helperMaxLines to InputDecoration and InputDecorationTheme (#39433)

Similar to errorMaxLines
parent ed1d5a8f
......@@ -283,6 +283,7 @@ class _HelperError extends StatefulWidget {
this.textAlign,
this.helperText,
this.helperStyle,
this.helperMaxLines,
this.errorText,
this.errorStyle,
this.errorMaxLines,
......@@ -291,6 +292,7 @@ class _HelperError extends StatefulWidget {
final TextAlign textAlign;
final String helperText;
final TextStyle helperStyle;
final int helperMaxLines;
final String errorText;
final TextStyle errorStyle;
final int errorMaxLines;
......@@ -372,6 +374,7 @@ class _HelperErrorState extends State<_HelperError> with SingleTickerProviderSta
style: widget.helperStyle,
textAlign: widget.textAlign,
overflow: TextOverflow.ellipsis,
maxLines: widget.helperMaxLines,
),
),
);
......@@ -2184,6 +2187,7 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
textAlign: textAlign,
helperText: decoration.helperText,
helperStyle: _getHelperStyle(themeData),
helperMaxLines: decoration.helperMaxLines,
errorText: decoration.errorText,
errorStyle: _getErrorStyle(themeData),
errorMaxLines: decoration.errorMaxLines,
......@@ -2304,6 +2308,7 @@ class InputDecoration {
this.labelStyle,
this.helperText,
this.helperStyle,
this.helperMaxLines,
this.hintText,
this.hintStyle,
this.hintMaxLines,
......@@ -2363,6 +2368,7 @@ class InputDecoration {
labelStyle = null,
helperText = null,
helperStyle = null,
helperMaxLines = null,
hintMaxLines = null,
errorText = null,
errorStyle = null,
......@@ -2436,6 +2442,19 @@ class InputDecoration {
/// The style to use for the [helperText].
final TextStyle helperStyle;
/// The maximum number of lines the [helperText] can occupy.
///
/// Defaults to null, which means that the [helperText] will be limited
/// to a single line with [TextOverflow.ellipsis].
///
/// This value is passed along to the [Text.maxLines] attribute
/// of the [Text] widget used to display the helper.
///
/// See also:
///
/// * [errorMaxLines], the equivalent but for the [errorText].
final int helperMaxLines;
/// Text that suggests what sort of input the field accepts.
///
/// Displayed on top of the input [child] (i.e., at the same location on the
......@@ -2485,6 +2504,10 @@ class InputDecoration {
///
/// This value is passed along to the [Text.maxLines] attribute
/// of the [Text] widget used to display the error.
///
/// See also:
///
/// * [helperMaxLines], the equivalent but for the [helperText].
final int errorMaxLines;
/// Whether the label floats on focus.
......@@ -2939,6 +2962,7 @@ class InputDecoration {
TextStyle labelStyle,
String helperText,
TextStyle helperStyle,
int helperMaxLines,
String hintText,
TextStyle hintStyle,
int hintMaxLines,
......@@ -2979,6 +3003,7 @@ class InputDecoration {
labelStyle: labelStyle ?? this.labelStyle,
helperText: helperText ?? this.helperText,
helperStyle: helperStyle ?? this.helperStyle,
helperMaxLines : helperMaxLines ?? this.helperMaxLines,
hintText: hintText ?? this.hintText,
hintStyle: hintStyle ?? this.hintStyle,
hintMaxLines: hintMaxLines ?? this.hintMaxLines,
......@@ -3024,6 +3049,7 @@ class InputDecoration {
return copyWith(
labelStyle: labelStyle ?? theme.labelStyle,
helperStyle: helperStyle ?? theme.helperStyle,
helperMaxLines : helperMaxLines ?? theme.helperMaxLines,
hintStyle: hintStyle ?? theme.hintStyle,
errorStyle: errorStyle ?? theme.errorStyle,
errorMaxLines: errorMaxLines ?? theme.errorMaxLines,
......@@ -3059,6 +3085,7 @@ class InputDecoration {
&& typedOther.labelStyle == labelStyle
&& typedOther.helperText == helperText
&& typedOther.helperStyle == helperStyle
&& typedOther.helperMaxLines == helperMaxLines
&& typedOther.hintText == hintText
&& typedOther.hintStyle == hintStyle
&& typedOther.hintMaxLines == hintMaxLines
......@@ -3103,6 +3130,7 @@ class InputDecoration {
labelStyle,
helperText,
helperStyle,
helperMaxLines,
hintText,
hintStyle,
hintMaxLines,
......@@ -3149,6 +3177,7 @@ class InputDecoration {
if (icon != null) 'icon: $icon',
if (labelText != null) 'labelText: "$labelText"',
if (helperText != null) 'helperText: "$helperText"',
if (helperMaxLines != null) 'helperMaxLines: "$helperMaxLines"',
if (hintText != null) 'hintText: "$hintText"',
if (hintMaxLines != null) 'hintMaxLines: "$hintMaxLines"',
if (errorText != null) 'errorText: "$errorText"',
......@@ -3206,6 +3235,7 @@ class InputDecorationTheme extends Diagnosticable {
const InputDecorationTheme({
this.labelStyle,
this.helperStyle,
this.helperMaxLines,
this.hintStyle,
this.errorStyle,
this.errorMaxLines,
......@@ -3245,6 +3275,19 @@ class InputDecorationTheme extends Diagnosticable {
/// The style to use for [InputDecoration.helperText].
final TextStyle helperStyle;
/// The maximum number of lines the [helperText] can occupy.
///
/// Defaults to null, which means that the [helperText] will be limited
/// to a single line with [TextOverflow.ellipsis].
///
/// This value is passed along to the [Text.maxLines] attribute
/// of the [Text] widget used to display the helper.
///
/// See also:
///
/// * [errorMaxLines], the equivalent but for the [errorText].
final int helperMaxLines;
/// The style to use for the [InputDecoration.hintText].
///
/// Also used for the [labelText] when the [labelText] is displayed on
......@@ -3268,6 +3311,10 @@ class InputDecorationTheme extends Diagnosticable {
///
/// This value is passed along to the [Text.maxLines] attribute
/// of the [Text] widget used to display the error.
///
/// See also:
///
/// * [helperMaxLines], the equivalent but for the [helperText].
final int errorMaxLines;
/// Whether the placeholder text floats to become a label on focus.
......@@ -3522,6 +3569,7 @@ class InputDecorationTheme extends Diagnosticable {
InputDecorationTheme copyWith({
TextStyle labelStyle,
TextStyle helperStyle,
int helperMaxLines,
TextStyle hintStyle,
TextStyle errorStyle,
int errorMaxLines,
......@@ -3547,6 +3595,7 @@ class InputDecorationTheme extends Diagnosticable {
return InputDecorationTheme(
labelStyle: labelStyle ?? this.labelStyle,
helperStyle: helperStyle ?? this.helperStyle,
helperMaxLines: helperMaxLines ?? this.helperMaxLines,
hintStyle: hintStyle ?? this.hintStyle,
errorStyle: errorStyle ?? this.errorStyle,
errorMaxLines: errorMaxLines ?? this.errorMaxLines,
......@@ -3576,6 +3625,7 @@ class InputDecorationTheme extends Diagnosticable {
return hashList(<dynamic>[
labelStyle,
helperStyle,
helperMaxLines,
hintStyle,
errorStyle,
errorMaxLines,
......@@ -3609,6 +3659,7 @@ class InputDecorationTheme extends Diagnosticable {
final InputDecorationTheme typedOther = other;
return typedOther.labelStyle == labelStyle
&& typedOther.helperStyle == helperStyle
&& typedOther.helperMaxLines == helperMaxLines
&& typedOther.hintStyle == hintStyle
&& typedOther.errorStyle == errorStyle
&& typedOther.errorMaxLines == errorMaxLines
......@@ -3638,6 +3689,7 @@ class InputDecorationTheme extends Diagnosticable {
const InputDecorationTheme defaultTheme = InputDecorationTheme();
properties.add(DiagnosticsProperty<TextStyle>('labelStyle', labelStyle, defaultValue: defaultTheme.labelStyle));
properties.add(DiagnosticsProperty<TextStyle>('helperStyle', helperStyle, defaultValue: defaultTheme.helperStyle));
properties.add(IntProperty('helperMaxLines', helperMaxLines, defaultValue: defaultTheme.helperMaxLines));
properties.add(DiagnosticsProperty<TextStyle>('hintStyle', hintStyle, defaultValue: defaultTheme.hintStyle));
properties.add(DiagnosticsProperty<TextStyle>('errorStyle', errorStyle, defaultValue: defaultTheme.errorStyle));
properties.add(IntProperty('errorMaxLines', errorMaxLines, defaultValue: defaultTheme.errorMaxLines));
......
......@@ -1026,6 +1026,103 @@ void main() {
expect(tester.getBottomLeft(find.text(kError1)), const Offset(12.0, 76.0));
});
testWidgets('InputDecoration helperMaxLines', (WidgetTester tester) async {
const String kHelper1 = 'e0';
const String kHelper2 = 'e0\ne1';
const String kHelper3 = 'e0\ne1\ne2';
await tester.pumpWidget(
buildInputDecorator(
isEmpty: true,
// isFocused: false (default)
decoration: const InputDecoration(
labelText: 'label',
helperText: kHelper3,
helperMaxLines: 3,
errorText: null,
filled: true,
),
),
);
// Overall height for this InputDecorator is 100dps:
//
// 12 - top padding
// 12 - floating label (ahem font size 16dps * 0.75 = 12)
// 4 - floating label / input text gap
// 16 - input text (ahem font size 16dps)
// 12 - bottom padding
// 8 - below the border padding
// 36 - helper text (3 lines, ahem font size 12dps)
expect(tester.getSize(find.byType(InputDecorator)), const Size(800.0, 100.0));
expect(tester.getTopLeft(find.text(kHelper3)), const Offset(12.0, 64.0));
expect(tester.getBottomLeft(find.text(kHelper3)), const Offset(12.0, 100.0));
// Overall height for this InputDecorator is 12 less than the first
// one, 88dps, because helperText only occupies two lines.
await tester.pumpWidget(
buildInputDecorator(
isEmpty: true,
// isFocused: false (default)
decoration: const InputDecoration(
labelText: 'label',
helperText: kHelper3,
helperMaxLines: 2,
errorText: null,
filled: true,
),
),
);
expect(tester.getSize(find.byType(InputDecorator)), const Size(800.0, 88.0));
expect(tester.getTopLeft(find.text(kHelper3)), const Offset(12.0, 64.0));
expect(tester.getBottomLeft(find.text(kHelper3)), const Offset(12.0, 88.0));
// Overall height for this InputDecorator is 12 less than the first
// one, 88dps, because helperText only occupies two lines.
await tester.pumpWidget(
buildInputDecorator(
isEmpty: true,
// isFocused: false (default)
decoration: const InputDecoration(
labelText: 'label',
helperText: kHelper2,
helperMaxLines: 3,
errorText: null,
filled: true,
),
),
);
expect(tester.getSize(find.byType(InputDecorator)), const Size(800.0, 88.0));
expect(tester.getTopLeft(find.text(kHelper2)), const Offset(12.0, 64.0));
expect(tester.getBottomLeft(find.text(kHelper2)), const Offset(12.0, 88.0));
// Overall height for this InputDecorator is 24 less than the first
// one, 88dps, because helperText only occupies one line.
await tester.pumpWidget(
buildInputDecorator(
isEmpty: true,
// isFocused: false (default)
decoration: const InputDecoration(
labelText: 'label',
helperText: kHelper1,
helperMaxLines: 3,
errorText: null,
filled: true,
),
),
);
expect(tester.getSize(find.byType(InputDecorator)), const Size(800.0, 76.0));
expect(tester.getTopLeft(find.text(kHelper1)), const Offset(12.0, 64.0));
expect(tester.getBottomLeft(find.text(kHelper1)), const Offset(12.0, 76.0));
});
testWidgets('InputDecorator prefix/suffix texts', (WidgetTester tester) async {
await tester.pumpWidget(
buildInputDecorator(
......@@ -2703,6 +2800,7 @@ void main() {
const InputDecorationTheme(
labelStyle: themeStyle,
helperStyle: themeStyle,
helperMaxLines: 5,
hintStyle: themeStyle,
errorStyle: themeStyle,
errorMaxLines: 4,
......@@ -2721,6 +2819,7 @@ void main() {
expect(decoration.labelStyle, decorationStyle);
expect(decoration.helperStyle, decorationStyle);
expect(decoration.helperMaxLines, 5);
expect(decoration.hintStyle, decorationStyle);
expect(decoration.errorStyle, decorationStyle);
expect(decoration.errorMaxLines, 4);
......@@ -3024,6 +3123,7 @@ void main() {
final String debugString = const InputDecorationTheme(
labelStyle: TextStyle(height: 1.0),
helperStyle: TextStyle(height: 2.0),
helperMaxLines: 5,
hintStyle: TextStyle(height: 3.0),
errorStyle: TextStyle(height: 4.0),
errorMaxLines: 5,
......@@ -3412,6 +3512,7 @@ void main() {
const InputDecorationTheme(
labelStyle: TextStyle(),
helperStyle: TextStyle(),
helperMaxLines: 6,
hintStyle: TextStyle(),
errorMaxLines: 5,
hasFloatingPlaceholder: false,
......@@ -3436,6 +3537,7 @@ void main() {
expect(description, <String>[
'labelStyle: TextStyle(<all styles inherited>)',
'helperStyle: TextStyle(<all styles inherited>)',
'helperMaxLines: 6',
'hintStyle: TextStyle(<all styles inherited>)',
'errorMaxLines: 5',
'hasFloatingPlaceholder: false',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment