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