likes
comments
collection
share

flutter: 打造自己的FormField

作者站长头像
站长
· 阅读数 8

Flutter提供了Form组件,方便开发者对表单输入进行统一操作,如输入内容校验、输入框重置以及输入内容保存等。Form的子孙必须是FormField类型,FormField是一个抽象类,部分属性的定义如下:

const FormField({
  ...
  FormFieldSetter<T> onSaved, //保存回调
  FormFieldValidator<T>  validator, //验证回调
  T initialValue, //初始值
  bool autovalidate = false, //是否自动校验。
})

FormStateFormState类,可以通过Form.of()GlobalKey获得。我们可以通过它来对Form的子孙FormField进行统一操作。常用的方法有:

  • FormState.validate():调用此方法后,会调用Form子孙FormFieldvalidate回调,如果有一个校验失败,则返回false,所有校验失败项都会返回用户返回的错误提示。

  • FormState.save():调用此方法后,会调用- Form子孙FormFieldsave回调,用于保存表单内容

  • FormState.reset():调用此方法后,会将子孙FormField的内容清空。

FormField本身的自定义实现较为复杂,所以官方提供了TextFormField这一组件,它继承自FormField类,用户通过这个组件可以对输入的内容进行上述几种常见操作。但是对于自定义的其他表单组件,比如我们自己实现了一个选择器selector,想把它放入Form里,验证和清空就不能使用Form自带的方法,如果表单中包含很多这类组件,校验、保存数据等常用的操作就显得非常麻烦,因此自己继承Formfield来加入到Form的统一操作是十分必要的,但是这方面的教程和资料在社区中难以查找。 因此本文希望给读者一个自定义Formfield的案例,让读者能够快速上手。我们以表单的重置(恢复初始值)为例,构建一个SelectorFormField ,让它能够设置初始值,并能够在Form执行reset的时候回到初始值,用同样的方法你也可以让表单实现所有组件在提交时统一检查,保存数据等操作。

1 目标

我们的目标是可以使用Formreset方法统一使Form中包含的所有选择器的值回到初始值。

2 选择器简介

首先我们先简要介绍一下自己封装的选择器selector,该选择器在使用时可自定义颜色、icon、大小、选项列表等配置,实现效果如图所示,在这里我们需要着重关注的属性是选项列表itemList、默认选项defaultValue、值改变后的回调函数selectChange

flutter: 打造自己的FormField

// 选项列表结构
class ListItem {
  final String value;
  final String label;
  const ListItem({
    this.value,
    this.label,
  });
}
List<ListItem> messageList = [
        ListItem(value: 'all', label: '全部'),
        ListItem(value: 'link', label: '链接'),
        ListItem(value: 'file', label: '文件'),
        ListItem(value: 'image', label: '图片/视频'),
        ListItem(value: 'miniprogram', label: '小程序'),
 ],

// 组件使用示例
Selector(
	backgroundColor: Colors.grey[200],
	width: 168,
	height: 32,
	icon: Icon(
		Icons.arrow_drop_down,
		color: context.colors.black,
		size: 16.0,
	),
	itemList: messageList,
	defaultValue: 'all',
	selectChange: handleChanged,
),

3 写一个可以改变和重置内容的FormFied

选择器在Form中的最主要交互就是【选择列表项目 ➡️ 改变选择值】,重置的主要交互就是【点击重置 ➡️ 将选择值恢复到初始值】,因此我们围绕这两个交互的最简单形式,设计一个FormFied,只包含三个元素,一个字符串用于显示当前选择的值,一个选择按钮用于改变选择的值,模拟选择行为,一个重置按钮将字符串恢复到初始值。 在SimpleField组件内,我们放置选择的字符串,和用于改变选择的值的按钮,用来模拟选择行为,我们先从外部传入默认值:“我是默认文字”,按下按钮后,通过didChange方法可以改变state内的值。

class SimpleFormField extends FormField<String> {
  SimpleFormField({
    String defaultValue,
  }) : super(
            initialValue: defaultValue,
            builder: (FormFieldState<String> state) {
              return Row(
                mainAxisSize: MainAxisSize.min,
                children: <Widget>[
                  Text(state.value),
                  IconButton(
                    icon: Icon(
                      Icons.radio_button_checked,
                    ),
                    onPressed: () {
                      state.didChange('嘿,文字改变了');
                    },
                  ),
                ],
              );
            });
}

实现的效果如下:

flutter: 打造自己的FormField

实现了在内部修改String的文字之后,我们在外部实现内容的重置,这也符合我们最终需要在Form中统一重置所有表单组件的结构设计。 对Form的状态进行重置的一般方法是定义一个Global_key,然后将key传入Form,需要重置时调用key当前状态的reset方法,具体代码如下:

final _key = GlobalKey<FormState>();

Form(
	key: _key,
	child: Row(
		mainAxisSize: MainAxisSize.max,
		mainAxisAlignment: MainAxisAlignment.center,
		children: [
			SimpleFormField(
				defaultValue: "我是默认文字",
			),
		TextButton(
			onPressed: () {
				_key.currentState.reset();
			},
		child: Text('重置')),
		],
	)
),

通过这种外层调用方式,Form会将我们自定义的SimpleFormField中的值恢复到初始值,实现效果如下:

flutter: 打造自己的FormField

这样我们就基本实现了一个简单的可以改变和重置内容的formfield。

4 将FormField封装在选择器组件外层

选择器的选择行为可以看作是改变FromFied的字符串值,因此我们只需要将FormField的状态值传入选择器作为显示的值,并在传入的回调函数中写入改变值的的行为,基本的封装代码如下所示:

class SelectorFormField extends FormField<String> {
  SelectorFormField({ // 外层接收所有参数,并一一写入内层组件
    SelectButtonSize size,
    double width,
    double height,
    Color backgroundColor,
    Color borderColor,
    bool noBorder,
    Widget icon,
    double listWidth,
    double listHeight,
    List itemList,
    String defaultValue,
    ValueChanged<String> selectChange,
  }) : super(
            initialValue: defaultValue,
            builder: (FormFieldState<String> state) {
              return Selector(
                  formValue: state.value, // 加入状态保存的值,用于内部选择值的显示
                  size: size,
                  width: width,
                  height: height,
                  backgroundColor: backgroundColor,
                  borderColor: borderColor,
                  noBorder: noBorder,
                  icon: icon,
                  listWidth: listWidth,
                  listHeight: listHeight,
                  itemList: itemList,
                  defaultValue: defaultValue,
                  onChange: (value) {  //回调函数在Formfield中改变选择的值,并向最外层传递
                    state.didChange(value);
                    selectChange(value);
                  });
            });
}

通过此类封装,只需要使用与selector同样的方法调用SelectorFormField,即可实现Formselector的统一操作,实现效果如下:

flutter: 打造自己的FormField 这里以表单重置为例,感兴趣的同学也可自行尝试表单验证validator或者数据存储onSaved等其他表单行为。