Usage of GlobalKey in Flutter

The role of GlobalKey

Let’s talk about the conclusion first, and the origin of this conclusion will be analyzed later: Each Widgetcorresponds to one Element, we can directly Widgetoperate on it, but we cannot directly operate Widgetthe corresponding one Element. It's the key GlobalKeyto direct access Element. Through GlobalKeycan get the Widgetcorresponding Element, such as get StatelessElementand StatefulElement. For example, if it is obtained StatefullElement, then we can get StatefulElementthe Stateobject.
 

Let's take the Formform as an example to analyze GlobalKeywhy Widgetthe corresponding one can be obtained Element.

GlobalKey Practical Example

There must be an input box for entering the user name and password for login, Flutterand we only implement it in the form of Formform + TextFormField. Now let 's talk about the simple use of Formsum . The login interface in the demo is as follows:TextFormField

insert image description here



Then we click the submit button without entering any characters, the effect is as follows:
 

 insert image description here

 
The code for the above layout is as follows:

import 'package:flutter/material.dart';

//使用GlobalKey来使用Form
class FormUseGlobalKeyDemo extends StatefulWidget {
  @override
  _FormState createState() {
    return _FormState();
  }
}


class _FormState extends State<FormUseGlobalKeyDemo> {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("使用GlobalKey的Form表单"),
      ),
      body: _createForm(),
    );
  }

  final _formKey = GlobalKey<FormState>();
  Widget _createForm() {
    return Form(
        key: _formKey,
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            TextFormField(
              validator: (value) {///输入字符校验
                if (value.isEmpty) {
                  return '请输入文字';
                }
                return null;
              },
            ),
            _createSubmitButton(),///创建submit按钮
          ],
        ),
    );
  }

  Widget _createSubmitButton() {
    return RaisedButton(
      onPressed: () {
        Form.of(context);
        if (_formKey.currentState.validate()) {///点击时开始非空验证
            print('验证通过');
          }
      },
      child: Text('Submit'),
    );
  }
}

GlobalKeyFirst initialize the object as shown above . Then set this object as Formthe key, and finally click the Submit button, we do not directly operate TextFormField, but through the non-empty verification of the content _formKey.currentState.validateof the input box . Its type TextFormFieldin the code is :_formKey.currentStateFormState

 class Form extends StatefulWidget {
  const Form({
    Key key,
    @required this.child,
   
  }) ;
  
  @override
  FormState createState() => FormState();

 //调用Form.of(context)也可以获取FormState对象
 //详情请看【Flutter之实战InheritedWidget详解】
  static FormState of(BuildContext context) {
    final _FormScope scope = context.inheritFromWidgetOfExactType(_FormScope);
    return scope?._formState;
  }

}

The principle of GlobalKey to obtain Element

 
 abstract class GlobalKey<T extends State<StatefulWidget>> extends Key {
  //一个静态的变量map集合
  static final Map<GlobalKey, Element> _registry = <GlobalKey, Element>{};
}

As can be seen from  GlobalKey<T extends State<StatefulWidget>> the class structure of , it GlobalKeyis mainly used to store state information  State<StatefulWidget>, Statewhich refers to StatefulWidget the state class, which is created by StatefulWidget the createStatemethod:

abstract class StatefulWidget extends Widget {
  //Key是个options的,可以设置也可以不设置
  const StatefulWidget({ Key key }) : super(key: key);
  @protected
  State createState();
}

Why GlobalKey.currentStatecan you get it through the above FormState? How are the two related? Find out now.

Let's take a look at the specific implementation GlobalKeyof the method:currentState

  T get currentState {
    //当前的Element对象
    final Element element = _currentElement;
    //检测是否是SatefulElement对象
    if (element is StatefulElement) {
      final StatefulElement statefulElement = element;
      //获取StatefulElement对象的State对象
      final State state = statefulElement.state;
      //如果状态匹配,则返回对应的T
      if (state is T)
        return state;
    }
    return null;
  }
  //_currentElement是一个map集合Map<GlobalKey, Element> 
  //该集合以GlobalKeyweight对象,其值保存的是Element。
  Element get _currentElement => _registry[this];
   

There GlobalKeyis a static _registry Mapcollection inside, which is regarded GlobalKeyas key and Elementvalue; the currentState method provided is to use the GlobalKeyobject as Keythe corresponding StatefulElement object, and then StatefulElement.stateobtain the specific value from it FormState, then when to fill the _registry collection with data Woolen cloth? Through the analysis of the correspondence between Fultter's Element and Widget, we know that a method Elementwill be called after creation mount:

   
  void mount(Element parent, dynamic newSlot) {
    ///省略部分代码
    if (widget.key is GlobalKey) {
      final GlobalKey key = widget.key;
      //将Element对象注册进来
      key._register(this);
    }
   
  }
  //GlobalKey的_register方法。
  void _register(Element element) {
    _registry[this] = element;
  }

It can be found that the mount method Elementinjects GlobalKeythe static map collection we created into! So GlobalKeythe effect is: * Holds the current object, so the current Widgetone can be obtained through the object, and the related methods of manipulation by obtaining the state object . For example , the validate() method performs a non-null checkElementGlobalKeyStatefulWidgetStatefullElementStatefullElementStateStateFormState .

In fact, we can also use the Form.of(context)method to obtain the FormStateobject, and then call the validate method to complete TextFormFieldthe non-empty check. For the principle, see the detailed analysis of Flutter's actual combat InheritedWidget

Full code: https://github.com/guoyanqiu/flutter_login

Guess you like

Origin blog.csdn.net/jdsjlzx/article/details/123577341