1. 程式人生 > 實用技巧 >flutter表單Form內部實現原理淺析

flutter表單Form內部實現原理淺析

使用示例

閱讀原理之前請可以先移步到: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()

進入原始碼

class Form extends StatefulWidget {
  ...
  const Form({
    Key key,
    

可以看到,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的方法非常清晰,遍歷FormFieldState型別的_fields集合,並逐個呼叫FormFieldState型別子元素的validate方法。從這裡可以知,FormFieldState型別的子元素,肯定跟TextFormField有關聯。

TextFormField和FormFieldState關係

看下TextFormField原始碼

class TextFormField extends FormField<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關聯

從上面分析可知,Form繼承StatefulWidget,FormState是From的State,Form一步呼叫所有關聯表單的方法validate是FormState的方法;TextFormField也是StatefulWidget型別,並且FormFieldState也是TextFormField的State;
再回頭看Form的validate最終呼叫的_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;
  }
  ...
}

可以看到_fields資料有變化在_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);
    ...
  }
}

從上可知:

  • FormState的_register和_unregister調用出現在FormFieldState裡,並且會把FormFieldState傳給_register和_unregister;
  • 在FormFieldState的build方法裡通過Form.of(context)呼叫_register將自己的FormFieldState傳給FormState並加入_fields;
  • 在FormFieldState的deactivate方法裡通過Form.of(context)呼叫_unregister將自己的FormFieldState從FormState的_fields中移掉;
    (未完待續。。。)


http://m.cntricycle.com/20201127/4884066.html
http://m.cntricycle.com/20201127/8628840.html
http://m.cntricycle.com/20201127/6226442.html
http://m.cntricycle.com/20201127/0660440.html
http://m.cntricycle.com/20201127/2404684.html
http://m.cntricycle.com/20201127/6824268.html
http://m.cntricycle.com/20201127/2620626.html
http://m.cntricycle.com/20201127/0640408.html
http://m.cntricycle.com/20201127/6044086.html
http://m.cntricycle.com/20201127/2868864.html
http://m.cntricycle.com/20201127/4822804.html
http://m.cntricycle.com/20201127/8224448.html
http://m.cntricycle.com/20201127/2428482.html
http://m.cntricycle.com/20201127/6048048.html
http://m.cntricycle.com/20201127/6428220.html
http://m.cntricycle.com/20201127/2426826.html
http://m.cntricycle.com/20201127/8646020.html
http://m.cntricycle.com/20201127/0406800.html
http://m.cntricycle.com/20201127/0666222.html
http://m.cntricycle.com/20201127/8680064.html
http://m.cntricycle.com/20201127/2480686.html
http://m.cntricycle.com/20201127/2246068.html
http://m.cntricycle.com/20201127/2802826.html
http://m.cntricycle.com/20201127/0420408.html
http://m.cntricycle.com/20201127/0040460.html
http://m.cntricycle.com/20201127/2640002.html
http://m.cntricycle.com/20201127/6026806.html
http://m.cntricycle.com/20201127/6228484.html
http://m.cntricycle.com/20201127/8862266.html
http://m.cntricycle.com/20201127/2600248.html