6.1 TextFormWidget 组件封装
预备知识
Form
继承自StatefulWidget
对象,它对应的状态类为FormState
。
Form
类的定义:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| class Form extends StatefulWidget {
final Widget child;
final WillPopCallback? onWillPop;
final VoidCallback? onChanged;
final AutovalidateMode autovalidateMode;
|
Form
的子孙元素必须是FormField
类型,FormField
是一个抽象类,定义几个属性,FormState
内部通过它们来完成操作,FormField
部分定义如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class FormField<T> extends StatefulWidget {
final FormFieldSetter<T>? onSaved;
final FormFieldValidator<T>? validator;
final T? initialValue;
final bool enabled;
final AutovalidateMode autovalidateMode;
|
TextFormField
为了方便使用,Flutter 提供了一个TextFormField
组件,它继承自FormField
类,也是TextField
的一个包装类,所以除了FormField
定义的属性之外,它还包括TextField
的属性。
FormState
为Form
的State
类,可以通过Form.of()
或GlobalKey
获得。我们可以通过它来对Form
的子孙FormField
进行统一操作。我们看看其常用的三个方法:
FormState.validate()
:调用此方法后,会调用Form
子孙FormField的validate
回调,如果有一个校验失败,则返回 false,所有校验失败项都会返回用户返回的错误提示。
FormState.save()
:调用此方法后,会调用Form
子孙FormField
的save
回调,用于保存表单内容
FormState.reset()
:调用此方法后,会将子孙FormField
的内容清空。
实现步骤:
第 1 步:定义类参数
lib/common/widgets/text_form.dart
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| class TextFormWidget extends StatefulWidget { final TextEditingController? controller;
final InputDecoration? decoration;
final String? Function(String?)? validator;
final bool? autofocus;
final String? labelText;
final bool? isMustBeEnter;
final bool? isObscure;
final bool? readOnly;
final TextInputType? keyboardType;
final List<TextInputFormatter>? inputFormatters;
final String? hintText;
final Function()? onTap;
const TextFormWidget({ Key? key, this.controller, this.autofocus = false, this.labelText, this.isMustBeEnter = false, this.validator, this.isObscure = false, this.decoration, this.keyboardType, this.inputFormatters, this.readOnly = false, this.onTap, this.hintText, }) : super(key: key);
@override _TextFormWidgetState createState() => _TextFormWidgetState(); }
|
第 2 步:build 函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| class _TextFormWidgetState extends State<TextFormWidget> { bool _isShowObscureIcon = false;
@override void initState() { super.initState(); _isShowObscureIcon = widget.isObscure!; }
@override Widget build(BuildContext context) { return TextFormField( onTap: widget.onTap, readOnly: widget.readOnly!, autofocus: widget.autofocus!, keyboardType: widget.keyboardType, controller: widget.controller, decoration: widget.isObscure == true ? InputDecoration( hintText: widget.hintText, labelText: widget.isMustBeEnter == true ? "* ${widget.labelText}" : widget.labelText, suffixIcon: IconButton( onPressed: () { setState(() { _isShowObscureIcon = !_isShowObscureIcon; }); }, icon: Icon( _isShowObscureIcon == true ? Icons.visibility : Icons.visibility_off, size: 15, color: AppColors.surfaceVariant, ), ), ) : InputDecoration( hintText: widget.hintText, labelText: widget.isMustBeEnter == true ? "* ${widget.labelText}" : widget.labelText, ), validator: widget.validator, obscureText: _isShowObscureIcon, inputFormatters: widget.inputFormatters, ); } }
|
第 3 步:调试界面
lib/pages/styles/styles_index/view.dart
1 2 3 4 5
| ListTile( onTap: () => Get.toNamed(RouteNames.stylesTextForm), title: const TextWidget.body1("form 表单"), ),
|
lib/pages/styles/text_form/controller.dart
1 2 3 4
| GlobalKey formKey = GlobalKey<FormState>();
TextEditingController unameController = TextEditingController(text: "ducafecat"); TextEditingController pwdController = TextEditingController(text: "123456");
|
1 2 3 4 5 6
| @override void onClose() { super.onClose(); unameController.dispose(); pwdController.dispose(); }
|
lib/pages/styles/text_form/view.dart
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| Widget _buildTextForm() { return Form( key: controller.formKey, autovalidateMode: AutovalidateMode.onUserInteraction, child: <Widget>[ TextFormWidget( keyboardType: TextInputType.emailAddress, controller: controller.unameController, labelText: "email", ), TextFormWidget( controller: controller.pwdController, labelText: "password", isObscure: true, ).marginOnly( bottom: 10, ), ButtonWidget.primary( "submit", onTap: () { if ((controller.formKey.currentState as FormState).validate()) { try {} finally {} } }, ).tight(width: 100, height: 40), ].toColumn()); }
Widget _buildView() { return SingleChildScrollView( child: _buildTextForm().padding( all: AppSpace.page, ), ); }
|
最后:运行
提交代码到 git