@@ -308,6 +308,7 @@ class _Shaker extends AnimatedWidget {
308
308
class _HelperError extends StatefulWidget {
309
309
const _HelperError ({
310
310
this .textAlign,
311
+ this .helper,
311
312
this .helperText,
312
313
this .helperStyle,
313
314
this .helperMaxLines,
@@ -318,6 +319,7 @@ class _HelperError extends StatefulWidget {
318
319
});
319
320
320
321
final TextAlign ? textAlign;
322
+ final Widget ? helper;
321
323
final String ? helperText;
322
324
final TextStyle ? helperStyle;
323
325
final int ? helperMaxLines;
@@ -339,6 +341,7 @@ class _HelperErrorState extends State<_HelperError> with SingleTickerProviderSta
339
341
Widget ? _helper;
340
342
Widget ? _error;
341
343
344
+ bool get _hasHelper => widget.helperText != null || widget.helper != null ;
342
345
bool get _hasError => widget.errorText != null || widget.error != null ;
343
346
344
347
@override
@@ -351,7 +354,7 @@ class _HelperErrorState extends State<_HelperError> with SingleTickerProviderSta
351
354
if (_hasError) {
352
355
_error = _buildError ();
353
356
_controller.value = 1.0 ;
354
- } else if (widget.helperText != null ) {
357
+ } else if (_hasHelper ) {
355
358
_helper = _buildHelper ();
356
359
}
357
360
_controller.addListener (_handleChange);
@@ -375,20 +378,23 @@ class _HelperErrorState extends State<_HelperError> with SingleTickerProviderSta
375
378
376
379
final Widget ? newError = widget.error;
377
380
final String ? newErrorText = widget.errorText;
381
+ final Widget ? newHelper = widget.helper;
378
382
final String ? newHelperText = widget.helperText;
379
383
final Widget ? oldError = old.error;
380
384
final String ? oldErrorText = old.errorText;
385
+ final Widget ? oldHelper = old.helper;
381
386
final String ? oldHelperText = old.helperText;
382
387
383
388
final bool errorStateChanged = (newError != null ) != (oldError != null );
384
389
final bool errorTextStateChanged = (newErrorText != null ) != (oldErrorText != null );
390
+ final bool helperStateChanged = (newHelper != null ) != (oldHelper != null );
385
391
final bool helperTextStateChanged = newErrorText == null && (newHelperText != null ) != (oldHelperText != null );
386
392
387
- if (errorStateChanged || errorTextStateChanged || helperTextStateChanged) {
393
+ if (errorStateChanged || errorTextStateChanged || helperStateChanged || helperTextStateChanged) {
388
394
if (newError != null || newErrorText != null ) {
389
395
_error = _buildError ();
390
396
_controller.forward ();
391
- } else if (newHelperText != null ) {
397
+ } else if (newHelper != null || newHelperText != null ) {
392
398
_helper = _buildHelper ();
393
399
_controller.reverse ();
394
400
} else {
@@ -398,12 +404,12 @@ class _HelperErrorState extends State<_HelperError> with SingleTickerProviderSta
398
404
}
399
405
400
406
Widget _buildHelper () {
401
- assert (widget.helperText != null );
407
+ assert (widget.helper != null || widget. helperText != null );
402
408
return Semantics (
403
409
container: true ,
404
410
child: FadeTransition (
405
411
opacity: Tween <double >(begin: 1.0 , end: 0.0 ).animate (_controller),
406
- child: Text (
412
+ child: widget.helper ?? Text (
407
413
widget.helperText! ,
408
414
style: widget.helperStyle,
409
415
textAlign: widget.textAlign,
@@ -441,7 +447,7 @@ class _HelperErrorState extends State<_HelperError> with SingleTickerProviderSta
441
447
Widget build (BuildContext context) {
442
448
if (_controller.isDismissed) {
443
449
_error = null ;
444
- if (widget.helperText != null ) {
450
+ if (_hasHelper ) {
445
451
return _helper = _buildHelper ();
446
452
} else {
447
453
_helper = null ;
@@ -463,7 +469,7 @@ class _HelperErrorState extends State<_HelperError> with SingleTickerProviderSta
463
469
return _buildError ();
464
470
}
465
471
466
- if (_error == null && widget.helperText != null ) {
472
+ if (_error == null && _hasHelper ) {
467
473
return _buildHelper ();
468
474
}
469
475
@@ -479,7 +485,7 @@ class _HelperErrorState extends State<_HelperError> with SingleTickerProviderSta
479
485
);
480
486
}
481
487
482
- if (widget.helperText != null ) {
488
+ if (_hasHelper ) {
483
489
return Stack (
484
490
children: < Widget > [
485
491
_buildHelper (),
@@ -2370,6 +2376,7 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
2370
2376
2371
2377
final Widget helperError = _HelperError (
2372
2378
textAlign: textAlign,
2379
+ helper: decoration.helper,
2373
2380
helperText: decoration.helperText,
2374
2381
helperStyle: _getHelperStyle (themeData, defaults),
2375
2382
helperMaxLines: decoration.helperMaxLines,
@@ -2575,6 +2582,7 @@ class InputDecoration {
2575
2582
this .labelText,
2576
2583
this .labelStyle,
2577
2584
this .floatingLabelStyle,
2585
+ this .helper,
2578
2586
this .helperText,
2579
2587
this .helperStyle,
2580
2588
this .helperMaxLines,
@@ -2622,6 +2630,7 @@ class InputDecoration {
2622
2630
this .alignLabelWithHint,
2623
2631
this .constraints,
2624
2632
}) : 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.' ),
2625
2634
assert (! (prefix != null && prefixText != null ), 'Declaring both prefix and prefixText is not supported.' ),
2626
2635
assert (! (suffix != null && suffixText != null ), 'Declaring both suffix and suffixText is not supported.' ),
2627
2636
assert (! (error != null && errorText != null ), 'Declaring both error and errorText is not supported.' );
@@ -2649,6 +2658,7 @@ class InputDecoration {
2649
2658
labelText = null ,
2650
2659
labelStyle = null ,
2651
2660
floatingLabelStyle = null ,
2661
+ helper = null ,
2652
2662
helperText = null ,
2653
2663
helperStyle = null ,
2654
2664
helperMaxLines = null ,
@@ -2802,12 +2812,32 @@ class InputDecoration {
2802
2812
/// {@endtemplate}
2803
2813
final TextStyle ? floatingLabelStyle;
2804
2814
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
+
2805
2831
/// Text that provides context about the [InputDecorator.child] 's value, such
2806
2832
/// as how the value will be used.
2807
2833
///
2808
2834
/// If non-null, the text is displayed below the [InputDecorator.child] , in
2809
2835
/// the same location as [errorText] . If a non-null [errorText] value is
2810
2836
/// 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.
2811
2841
final String ? helperText;
2812
2842
2813
2843
/// The style to use for the [helperText] .
@@ -3536,6 +3566,7 @@ class InputDecoration {
3536
3566
String ? labelText,
3537
3567
TextStyle ? labelStyle,
3538
3568
TextStyle ? floatingLabelStyle,
3569
+ Widget ? helper,
3539
3570
String ? helperText,
3540
3571
TextStyle ? helperStyle,
3541
3572
int ? helperMaxLines,
@@ -3590,6 +3621,7 @@ class InputDecoration {
3590
3621
labelText: labelText ?? this .labelText,
3591
3622
labelStyle: labelStyle ?? this .labelStyle,
3592
3623
floatingLabelStyle: floatingLabelStyle ?? this .floatingLabelStyle,
3624
+ helper: helper ?? this .helper,
3593
3625
helperText: helperText ?? this .helperText,
3594
3626
helperStyle: helperStyle ?? this .helperStyle,
3595
3627
helperMaxLines : helperMaxLines ?? this .helperMaxLines,
@@ -3695,6 +3727,7 @@ class InputDecoration {
3695
3727
&& other.labelText == labelText
3696
3728
&& other.labelStyle == labelStyle
3697
3729
&& other.floatingLabelStyle == floatingLabelStyle
3730
+ && other.helper == helper
3698
3731
&& other.helperText == helperText
3699
3732
&& other.helperStyle == helperStyle
3700
3733
&& other.helperMaxLines == helperMaxLines
@@ -3752,6 +3785,7 @@ class InputDecoration {
3752
3785
labelText,
3753
3786
floatingLabelStyle,
3754
3787
labelStyle,
3788
+ helper,
3755
3789
helperText,
3756
3790
helperStyle,
3757
3791
helperMaxLines,
@@ -3810,6 +3844,7 @@ class InputDecoration {
3810
3844
if (label != null ) 'label: $label ' ,
3811
3845
if (labelText != null ) 'labelText: "$labelText "' ,
3812
3846
if (floatingLabelStyle != null ) 'floatingLabelStyle: "$floatingLabelStyle "' ,
3847
+ if (helper != null ) 'helper: "$helper "' ,
3813
3848
if (helperText != null ) 'helperText: "$helperText "' ,
3814
3849
if (helperMaxLines != null ) 'helperMaxLines: "$helperMaxLines "' ,
3815
3850
if (hintText != null ) 'hintText: "$hintText "' ,
0 commit comments