@@ -308,6 +308,7 @@ class _Shaker extends AnimatedWidget {
308308class _HelperError extends StatefulWidget {
309309 const _HelperError ({
310310 this .textAlign,
311+ this .helper,
311312 this .helperText,
312313 this .helperStyle,
313314 this .helperMaxLines,
@@ -318,6 +319,7 @@ class _HelperError extends StatefulWidget {
318319 });
319320
320321 final TextAlign ? textAlign;
322+ final Widget ? helper;
321323 final String ? helperText;
322324 final TextStyle ? helperStyle;
323325 final int ? helperMaxLines;
@@ -339,6 +341,7 @@ class _HelperErrorState extends State<_HelperError> with SingleTickerProviderSta
339341 Widget ? _helper;
340342 Widget ? _error;
341343
344+ bool get _hasHelper => widget.helperText != null || widget.helper != null ;
342345 bool get _hasError => widget.errorText != null || widget.error != null ;
343346
344347 @override
@@ -351,7 +354,7 @@ class _HelperErrorState extends State<_HelperError> with SingleTickerProviderSta
351354 if (_hasError) {
352355 _error = _buildError ();
353356 _controller.value = 1.0 ;
354- } else if (widget.helperText != null ) {
357+ } else if (_hasHelper ) {
355358 _helper = _buildHelper ();
356359 }
357360 _controller.addListener (_handleChange);
@@ -375,20 +378,23 @@ class _HelperErrorState extends State<_HelperError> with SingleTickerProviderSta
375378
376379 final Widget ? newError = widget.error;
377380 final String ? newErrorText = widget.errorText;
381+ final Widget ? newHelper = widget.helper;
378382 final String ? newHelperText = widget.helperText;
379383 final Widget ? oldError = old.error;
380384 final String ? oldErrorText = old.errorText;
385+ final Widget ? oldHelper = old.helper;
381386 final String ? oldHelperText = old.helperText;
382387
383388 final bool errorStateChanged = (newError != null ) != (oldError != null );
384389 final bool errorTextStateChanged = (newErrorText != null ) != (oldErrorText != null );
390+ final bool helperStateChanged = (newHelper != null ) != (oldHelper != null );
385391 final bool helperTextStateChanged = newErrorText == null && (newHelperText != null ) != (oldHelperText != null );
386392
387- if (errorStateChanged || errorTextStateChanged || helperTextStateChanged) {
393+ if (errorStateChanged || errorTextStateChanged || helperStateChanged || helperTextStateChanged) {
388394 if (newError != null || newErrorText != null ) {
389395 _error = _buildError ();
390396 _controller.forward ();
391- } else if (newHelperText != null ) {
397+ } else if (newHelper != null || newHelperText != null ) {
392398 _helper = _buildHelper ();
393399 _controller.reverse ();
394400 } else {
@@ -398,12 +404,12 @@ class _HelperErrorState extends State<_HelperError> with SingleTickerProviderSta
398404 }
399405
400406 Widget _buildHelper () {
401- assert (widget.helperText != null );
407+ assert (widget.helper != null || widget. helperText != null );
402408 return Semantics (
403409 container: true ,
404410 child: FadeTransition (
405411 opacity: Tween <double >(begin: 1.0 , end: 0.0 ).animate (_controller),
406- child: Text (
412+ child: widget.helper ?? Text (
407413 widget.helperText! ,
408414 style: widget.helperStyle,
409415 textAlign: widget.textAlign,
@@ -441,7 +447,7 @@ class _HelperErrorState extends State<_HelperError> with SingleTickerProviderSta
441447 Widget build (BuildContext context) {
442448 if (_controller.isDismissed) {
443449 _error = null ;
444- if (widget.helperText != null ) {
450+ if (_hasHelper ) {
445451 return _helper = _buildHelper ();
446452 } else {
447453 _helper = null ;
@@ -463,7 +469,7 @@ class _HelperErrorState extends State<_HelperError> with SingleTickerProviderSta
463469 return _buildError ();
464470 }
465471
466- if (_error == null && widget.helperText != null ) {
472+ if (_error == null && _hasHelper ) {
467473 return _buildHelper ();
468474 }
469475
@@ -479,7 +485,7 @@ class _HelperErrorState extends State<_HelperError> with SingleTickerProviderSta
479485 );
480486 }
481487
482- if (widget.helperText != null ) {
488+ if (_hasHelper ) {
483489 return Stack (
484490 children: < Widget > [
485491 _buildHelper (),
@@ -2370,6 +2376,7 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
23702376
23712377 final Widget helperError = _HelperError (
23722378 textAlign: textAlign,
2379+ helper: decoration.helper,
23732380 helperText: decoration.helperText,
23742381 helperStyle: _getHelperStyle (themeData, defaults),
23752382 helperMaxLines: decoration.helperMaxLines,
@@ -2575,6 +2582,7 @@ class InputDecoration {
25752582 this .labelText,
25762583 this .labelStyle,
25772584 this .floatingLabelStyle,
2585+ this .helper,
25782586 this .helperText,
25792587 this .helperStyle,
25802588 this .helperMaxLines,
@@ -2622,6 +2630,7 @@ class InputDecoration {
26222630 this .alignLabelWithHint,
26232631 this .constraints,
26242632 }) : assert (! (label != null && labelText != null ), 'Declaring both label and labelText is not supported.' ),
2633+ assert (! (helper != null && helperText != null ), 'Declaring both helper and helperText is not supported.' ),
26252634 assert (! (prefix != null && prefixText != null ), 'Declaring both prefix and prefixText is not supported.' ),
26262635 assert (! (suffix != null && suffixText != null ), 'Declaring both suffix and suffixText is not supported.' ),
26272636 assert (! (error != null && errorText != null ), 'Declaring both error and errorText is not supported.' );
@@ -2649,6 +2658,7 @@ class InputDecoration {
26492658 labelText = null ,
26502659 labelStyle = null ,
26512660 floatingLabelStyle = null ,
2661+ helper = null ,
26522662 helperText = null ,
26532663 helperStyle = null ,
26542664 helperMaxLines = null ,
@@ -2802,12 +2812,32 @@ class InputDecoration {
28022812 /// {@endtemplate}
28032813 final TextStyle ? floatingLabelStyle;
28042814
2815+ /// Optional widget that appears below the [InputDecorator.child] .
2816+ ///
2817+ /// If non-null, the [helper] is displayed below the [InputDecorator.child] , in
2818+ /// the same location as [error] . If a non-null [error] or [errorText] value is
2819+ /// specified then the [helper] is not shown.
2820+ ///
2821+ /// {@tool dartpad}
2822+ /// This example shows a `TextField` with a [Text.rich] widget as the [helper] .
2823+ /// The widget contains [Text] and [Icon] widgets with different styles.
2824+ ///
2825+ /// ** See code in examples/api/lib/material/input_decorator/input_decoration.helper.0.dart **
2826+ /// {@end-tool}
2827+ ///
2828+ /// Only one of [helper] and [helperText] can be specified.
2829+ final Widget ? helper;
2830+
28052831 /// Text that provides context about the [InputDecorator.child] 's value, such
28062832 /// as how the value will be used.
28072833 ///
28082834 /// If non-null, the text is displayed below the [InputDecorator.child] , in
28092835 /// the same location as [errorText] . If a non-null [errorText] value is
28102836 /// specified then the helper text is not shown.
2837+ ///
2838+ /// If a more elaborate helper text is required, consider using [helper] instead.
2839+ ///
2840+ /// Only one of [helper] and [helperText] can be specified.
28112841 final String ? helperText;
28122842
28132843 /// The style to use for the [helperText] .
@@ -3536,6 +3566,7 @@ class InputDecoration {
35363566 String ? labelText,
35373567 TextStyle ? labelStyle,
35383568 TextStyle ? floatingLabelStyle,
3569+ Widget ? helper,
35393570 String ? helperText,
35403571 TextStyle ? helperStyle,
35413572 int ? helperMaxLines,
@@ -3590,6 +3621,7 @@ class InputDecoration {
35903621 labelText: labelText ?? this .labelText,
35913622 labelStyle: labelStyle ?? this .labelStyle,
35923623 floatingLabelStyle: floatingLabelStyle ?? this .floatingLabelStyle,
3624+ helper: helper ?? this .helper,
35933625 helperText: helperText ?? this .helperText,
35943626 helperStyle: helperStyle ?? this .helperStyle,
35953627 helperMaxLines : helperMaxLines ?? this .helperMaxLines,
@@ -3695,6 +3727,7 @@ class InputDecoration {
36953727 && other.labelText == labelText
36963728 && other.labelStyle == labelStyle
36973729 && other.floatingLabelStyle == floatingLabelStyle
3730+ && other.helper == helper
36983731 && other.helperText == helperText
36993732 && other.helperStyle == helperStyle
37003733 && other.helperMaxLines == helperMaxLines
@@ -3752,6 +3785,7 @@ class InputDecoration {
37523785 labelText,
37533786 floatingLabelStyle,
37543787 labelStyle,
3788+ helper,
37553789 helperText,
37563790 helperStyle,
37573791 helperMaxLines,
@@ -3810,6 +3844,7 @@ class InputDecoration {
38103844 if (label != null ) 'label: $label ' ,
38113845 if (labelText != null ) 'labelText: "$labelText "' ,
38123846 if (floatingLabelStyle != null ) 'floatingLabelStyle: "$floatingLabelStyle "' ,
3847+ if (helper != null ) 'helper: "$helper "' ,
38133848 if (helperText != null ) 'helperText: "$helperText "' ,
38143849 if (helperMaxLines != null ) 'helperMaxLines: "$helperMaxLines "' ,
38153850 if (hintText != null ) 'hintText: "$hintText "' ,
0 commit comments