使用示例
阅读原理之前可以先移步到:flutter 表单Form使用示例,大致了解下Form怎么使用。
实现原理分析
从上面例子可知,主要用到Form+TextFormField,那么我们就从Form+TextFormField入手来分析。
Form+TextFormField结构上的关系
代码我做了精简版,主要为了突出结构,如下:
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
Form(
key:_formKey,
child:
...
TextFormField(
validator: (value) {
...
return xxx;
},
)
...
TextFormField(
validator: (value) {
...
return xxx;
},
)
...
从上面可以知道,Form是容器,将所有关联的TextFormField装在里面,也就是说Form和所有关联的TextFormField在同一棵树结构上,Form节点是所有关联TextFormField的父节点,先记住这个结论。
Form如何一步校验所有关联的TextFormField
Form validate方法内部实现
之前使用Form一步校验所有表单时,就比较好奇Form是怎么和TextFormField产生关联的,就想看看它是怎么实现的。Form一步校验所有表单的方法是调用如下:
_formKey.currentState.validate()
进入Form源码
class Form extends StatefulWidget {
...
const Form({
Key key,
@required this.child,
this.autovalidate = false,
this.onWillPop,
this.onChanged,
})
...
}
class FormState extends State<Form> {
int _generation = 0;
final Set<FormFieldState<dynamic>> _fields = <FormFieldState<dynamic>>{};
...
void _forceRebuild() {
setState(() {
++_generation;
});
}
bool validate() {
_forceRebuild();
return _validate();
}
bool _validate() {
bool hasError = false;
for (FormFieldState<dynamic> field in _fields)
hasError = !field.validate() || hasError;
return !hasError;
}
...
}
可以看到,Form继承StatefulWidget,Form一步调用所有关联表单的方法validate是FormState的方法,validate方法里最终调用_validate方法
bool _validate() {
bool hasError = false;
for (FormFieldState<dynamic> field in _fields)
hasError = !field.validate() || hasError;
return !hasError;
}
_validate里实现逻辑比较清晰:
- _fields:FormFieldState类型的集合
- field.validate():调用FormFieldState类型元素的validate方法
- !field.validate() || hasError:只要有一个field.validate() 返回false,hasError值就为true(||或运算:两个变量参与||运算时,当两个变量有一个为true时,结果即为true,只有当两个变量均为false时结果为false)
- 翻译过来就是:遍历FormFieldState类型的集合_fields,并逐个调用FormFieldState类型子元素的validate方法,当有一个FormFieldState类型子元素的validate方法返回false时(注:这里是全部FormFieldState类型子元素都会调用validate),_validate就返回false,FormState的validate方法也返回false,也就是Form中有校验不合格的表单。从这里可以知,FormFieldState类型的子元素,肯定跟TextFormField有关联。
TextFormField和FormFieldState关系
看下TextFormField源码
class TextFormField extends FormField<String> {
...
@override
_TextFormFieldState createState() => _TextFormFieldState();
}
class _TextFormFieldState extends FormFieldState<String> {
...
}
可以看到TextFormField继承FormField,并且返回一个FormFieldState类型的State,这结构跟StatefulWidget类似;
再看下FormField源码
class FormField<T> extends StatefulWidget {
...
@override
FormFieldState<T> createState() => FormFieldState<T>();
}
class FormFieldState<T> extends State<FormField<T>> {
...
}
由此可知,FormField继承StatefulWidget,FormFieldState为FormField的State,所以TextFormField也是StatefulWidget类型,并且FormFieldState也是TextFormField的State。
Form和TextFormField关联
从上面分析可知:
(1)、Form继承StatefulWidget,FormState是From的State,Form一步校验所有关联表单的方法最终调用的是FormState的validate方法;
(2)、FormState的validate方法:遍历FormFieldState类型的集合,并逐个调用FormFieldState类型子元素的validate方法,当有一个FormFieldState类型子元素的validate方法返回false时,FormState的validate方法也返回false,表示Form中有校验不合格的表单;
(3)、TextFormField也是StatefulWidget类型,并且FormFieldState是TextFormField的State;
再回头看Form的validate方法,最终调用的FormState的_validate方法:
class FormState extends State<Form> {
final Set<FormFieldState<dynamic>> _fields = <FormFieldState<dynamic>>{};
...
bool _validate() {
bool hasError = false;
for (FormFieldState<dynamic> field in _fields)
hasError = !field.validate() || hasError;
return !hasError;
}
...
}
_validate主要实现遍历FormFieldState类型的集合_fields,并逐个调用FormFieldState类型子元素的validate方法。
这里FormFieldState类型的_fields集合数据从哪里来呢?
class FormState extends State<Form> {
...
final Set<FormFieldState<dynamic>> _fields = <FormFieldState<dynamic>>{};
void _register(FormFieldState<dynamic> field) {
_fields.add(field);
}
void _unregister(FormFieldState<dynamic> field) {
_fields.remove(field);
}
...
bool _validate() {
bool hasError = false;
for (FormFieldState<dynamic> field in _fields)
hasError = !field.validate() || hasError;
return !hasError;
}
...
}
可以看到FormFieldState类型的集合_fields的数据变化是在_register和_unregister方法调用的时侯,这样我们只需要找到FormState的_register和_unregister方法在哪调用就可以知道FormFieldState类型的集合从哪里来了。
FormState的_register和_unregister方法调用地方:
class FormFieldState<T> extends State<FormField<T>> {
...
@override
void deactivate() {
Form.of(context)?._unregister(this);
super.deactivate();
}
@override
Widget build(BuildContext context) {
...
Form.of(context)?._register(this);
...
}
bool validate() {
...
}
}
从上可知:
- FormState的_register和_unregister调用出现在FormFieldState里,并会把自己传给_register和_unregister;
- 在FormFieldState的build方法中,通过Form.of(context)调用_register将自己传给FormState,并加入_fields集合;
- 在FormFieldState的deactivate方法中,通过Form.of(context)调用_unregister将自己传给FormState,并从_fields集合中移掉;
由于FormFieldState是TextFormField的State,FormState是From的State,FormFieldState通过Form.of(context)将自己传给FormState,FormState保存FormFieldState的集合,这样FormState就可以调用就FormFieldState的方法了,Form也就和TextFormField关联起来了。
网友评论