Flutter中GlobalKey的用法
Posted 一叶飘舟
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Flutter中GlobalKey的用法相关的知识,希望对你有一定的参考价值。
GlobalKey的作用
先说结论,后文会分析此结论的由来: 每个Widget
都对应一个Element
,我们可以直接对Widget
进行操作,但是无法直接操作Widget
对应的Element
。而GlobalKey
就是那把直接访问Element
的钥匙。通过GlobalKey
可以获取到Widget
对应的Element
,比如获取StatelessElement
和StatefulElement
. 比如如果获取到了StatefullElement
,那么我们就可以获取StatefulElement
的State
对象。
下面我们就以Form
表单为例来分析GlobalKey
为什么可以获取Widget
对应的Element
。
GlobalKey实战举例
登录肯定要有输入用户名和密码的输入框,在Flutter
中我们只用Form
表单+TextFormField
的形式加以实现。现在就来讲讲Form
和TextFormField
的简单使用,demo中登录界面如下:
然后我们在不输入任何字符的情况下点击submit按钮,效果如下所示:
上图布局的代码如下所示:
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'),
);
如上所示首先初始化GlobalKey
对象。然后将此对象设置为Form
的key,最后再点击Submit按钮的时候,我们没有直接操作TextFormField
,而是通过_formKey.currentState.validate
对输入框TextFormField
的内容进行非空验证。代码中的_formKey.currentState
其类型是FormState
:
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;
GlobalKey获取Element的原理
abstract class GlobalKey<T extends State<StatefulWidget>> extends Key
//一个静态的变量map集合
static final Map<GlobalKey, Element> _registry = <GlobalKey, Element>;
从 GlobalKey<T extends State<StatefulWidget>>
的类结构可以看出,GlobalKey
主要用来存储状态信息 State<StatefulWidget>
,State
指的是StatefulWidget
的状态类,通过StatefulWidget
的createState
方法创建:
abstract class StatefulWidget extends Widget
//Key是个options的,可以设置也可以不设置
const StatefulWidget( Key key ) : super(key: key);
@protected
State createState();
上文中为什么通过GlobalKey.currentState
就可以获取到FormState
呢?二者是怎么关联起来的呢?现在就来一探究竟。
先来看看GlobalKey
的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];
在GlobalKey
内部有一个静态的的_registry Map
集合,该集合以GlobalKey
为key,以Element
为value;其提供的currentState
方法就是以GlobalKey
对象为Key
获取对应的StatefulElement
对象,然后从StatefulElement.state
里获取具体的值FormState
,那么什么时候往_registry 集合里填充数据呢?通过Fultter之Element和Widget对应关系解析我们知道一个Element
在创建之后会调用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;
可以发现在mount方法将我们创建的Element
注入到GlobalKey
的静态map集合中去!所以GlobalKey
的作用就是:*持有当前Widget
的Element
对象,因此通过GlobalKey
对象可以获取到当前StatefulWidget
的StatefullElement
,在通过StatefullElement
获取State
状态对象,从而操控State
的相关方法。比如FormState
的validate()方法进行非空校验。
事实上我们还可以使用Form.of(context)
方法也可以获到FormState
对象,然后调用validate方法完成TextFormField
的非空校验,其中原理,详细解析见Flutter之实战InheritedWidget详解
完整代码:https://github.com/guoyanqiu/flutter_login
以上是关于Flutter中GlobalKey的用法的主要内容,如果未能解决你的问题,请参考以下文章
为啥 Flutter 中的 Form 需要 GlobalKey?