diff --git a/packages/flutter/lib/src/material/text_form_field.dart b/packages/flutter/lib/src/material/text_form_field.dart index df4d79fff9..bf2834a2be 100644 --- a/packages/flutter/lib/src/material/text_form_field.dart +++ b/packages/flutter/lib/src/material/text_form_field.dart @@ -71,7 +71,7 @@ class TextFormField extends FormField { FormFieldSetter onSaved, FormFieldValidator validator, List inputFormatters, - bool enabled, + bool enabled = true, Brightness keyboardAppearance, EdgeInsets scrollPadding = const EdgeInsets.all(20.0), }) : assert(initialValue == null || controller == null), @@ -90,6 +90,7 @@ class TextFormField extends FormField { onSaved: onSaved, validator: validator, autovalidate: autovalidate, + enabled: enabled, builder: (FormFieldState field) { final _TextFormFieldState state = field; final InputDecoration effectiveDecoration = (decoration ?? const InputDecoration()) diff --git a/packages/flutter/lib/src/widgets/form.dart b/packages/flutter/lib/src/widgets/form.dart index ff0d5daa6c..b34d974577 100644 --- a/packages/flutter/lib/src/widgets/form.dart +++ b/packages/flutter/lib/src/widgets/form.dart @@ -227,6 +227,7 @@ class FormField extends StatefulWidget { this.validator, this.initialValue, this.autovalidate = false, + this.enabled = true, }) : assert(builder != null), super(key: key); @@ -256,6 +257,13 @@ class FormField extends StatefulWidget { /// autovalidates, this value will be ignored. final bool autovalidate; + /// Whether the form is able to receive user input. + /// + /// Defaults to true. If [autovalidate] is true, the field will be validated. + /// Likewise, if this field is false, the widget will not be validated + /// regardless of [autovalidate]. + final bool enabled; + @override FormFieldState createState() => FormFieldState(); } @@ -344,7 +352,8 @@ class FormFieldState extends State> { @override Widget build(BuildContext context) { - if (widget.autovalidate) + // Only autovalidate if the widget is also enabled + if (widget.autovalidate && widget.enabled) _validate(); Form.of(context)?._register(this); return widget.builder(this); diff --git a/packages/flutter/test/material/text_form_field_test.dart b/packages/flutter/test/material/text_form_field_test.dart index b80e155806..4ad6c40026 100644 --- a/packages/flutter/test/material/text_form_field_test.dart +++ b/packages/flutter/test/material/text_form_field_test.dart @@ -114,4 +114,52 @@ void main() { await tester.pump(); expect(_validateCalled, 2); }); + + testWidgets('validate is not called if widget is disabled', (WidgetTester tester) async { + int _validateCalled = 0; + + await tester.pumpWidget( + MaterialApp( + home: Material( + child: Center( + child: TextFormField( + enabled: false, + autovalidate: true, + validator: (String value) { _validateCalled += 1; return null; }, + ), + ), + ), + ), + ); + + expect(_validateCalled, 0); + await tester.showKeyboard(find.byType(TextField)); + await tester.enterText(find.byType(TextField), 'a'); + await tester.pump(); + expect(_validateCalled, 0); + }); + + testWidgets('validate is called if widget is enabled', (WidgetTester tester) async { + int _validateCalled = 0; + + await tester.pumpWidget( + MaterialApp( + home: Material( + child: Center( + child: TextFormField( + enabled: true, + autovalidate: true, + validator: (String value) { _validateCalled += 1; return null; }, + ), + ), + ), + ), + ); + + expect(_validateCalled, 1); + await tester.showKeyboard(find.byType(TextField)); + await tester.enterText(find.byType(TextField), 'a'); + await tester.pump(); + expect(_validateCalled, 2); + }); }