GlobalKey的作用
先说结论,后文会分析此结论的由来: 每个
Widget
都对应一个
Element
,我们可以直接对
Widget
进行操作,但是无法直接操作
Widget
对应的
Element
。而
GlobalKey
就是那把直接访问
Element
的钥匙。通过
GlobalKey
可以获取到
Widget
对应的
Element
,比如获取
StatelessElement
和
StatefulElement
. 比如如果获取到了
StatefullElement
,那么我们就可以获取
StatefulElement
的
State
对象。
下面我们就以
Form
表单为例来分析
GlobalKey
为什么可以获取
Widget
对应的
Element
。
登录肯定要有输入用户名和密码的输入框,在
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;
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
当一个主页面比较复杂时,会包含多个widget,如果直接调用setState,会遍历所有子Widget的build,这是非常不必要的性能开销,有没有单独刷新指定Widget的方式呢?这个时候就要用到GlobalKey了
globakey 需要包裹你要更新的子weight
import 'package:cell_input/globalkey/button.dart';
import 'package:cell_input/globalkey/text.dart';
import
我们在上一章说到,同一级中相同类型的Widget不给它传Key的话,Flutter有时候就会出现分不清它们之间的对应关系,尤其是Widget之间的顺序发生改变的时候. 此时,我们就需要传个key给它.
Key的种类
Key有两个子类:
LocalKey 局部键,在同一级中要唯一,可以理解为同级唯一性
GlobalKey 全局键 , 在整个App中必须是唯一的.
从性能上来讲,如果不需要用到GlobalKey的话,尽量不用,LocalKey因为只对比同一级别,因此会快很多.上一章也说过,在父级或者子级是不
Flutter Key的原理和使用(一) 没有Key会发生什么
Flutter Key的原理和使用 (二) Widget 和 Element 的对应关系
Flutter Key的原理和使用(三) LocalKey的三种类型
上一章,因为标题的原因哈,没有介绍到关于GlobalKey的内容,今天来讲一讲GlobalKey.
GlobalKey是在整个应用程序中唯一的键。
我们之前讲到,LocalKey是局部键,所以出现层级改变的时候:
Column(
children: [
Box(Color
class SwitcherWidget extends StatefulWidget {
SwitcherWidget({Key key}):super(key:key);
@override
Swit.
博主打算通过登录功能来总结一下Flutter的相关知识点。为什么选择登陆功能呢?因为登录功能逻辑简单,很好抽象,功能也很普遍,这也是博主以此为突破口写android MVC和MVP探讨的原因。本系列应该不长,初步估计也就三篇左右,通过层层递进,慢慢地会勾勒出一个完整的登陆功能的demo,demo的源码点此可得。俗话说站在巨人的肩膀上成长的更快,当然这个俗话是我瞎篇水字数的,本系列博文的重要参考资料...
GlobalKey只能单独使用不能重复使用,不然会报Duplicate GlobalKey detected in widget tree.当然你可以定义多个GlobalKey。当我们需要找到一个数据时,我们给这个组件定义一个GlobalKey。
_globalKey.currentState:获取所定义的State状态
_globalKey.currentWidget:获取所定义的
如果PageA没有被打开过,调用 PageAState.currentInstance().reloadData()是会出现空指针的。在 PageB 里调用 PageAState 的 reloadData() 方法。PageA的定义如下。
前言作为系列文章的第三篇,继篇章一和篇章二之后,本篇将为你着重展示:Flutter开发过程的打包流程、APP包对比、细节技巧与问题处理。本篇主要描述的Flutter的打包、在开发过程中遇到的各类问题与细节,算是对上两篇的补全。一、打包首先我们先看结果,如下表所示,是 Flutter 与 React Native 、IOS 与 Android 的纵向与横向对比 。从上表我们可以看到:Fluuter的...
当你有一个滑动列表,你通过某一个 Item 跳转到了一个新的页面,当你返回之前的列表页面时,你发现滑动的距离回到了顶部。LocalKey 直接继承至 Key,它应用于拥有相同父 Element 的小部件进行比较的情况,也就是上述例子中,有一个多子 Widget 中需要对它的子 widget 进行移动处理,这时候你应该使用Localkey。如果您有一个 Todo List 应用程序,它将会记录你需要完成的事情。如果你有一个生日应用,它可以记录某个人的生日,并用列表显示出来,同样的还是需要有一个滑动删除操作。.
这几天想着需要一个Flutter的Toast, 一开始的想法就是自己定义一个简单用用, 也看到有人提供了相关的 fluttertoast组件, 但是因为是学习Flutter, 所以感觉还是自己实现一个比较好, 索性网络上也有不少方法…
这里主要是使用Overlay来进行Toast的实现, 用过RN的teaset 基本对Overlay不陌生, 当然还是需要重新认识一下Flutter下的Overlay
Flutter 89: 图解基本 Overlay 悬浮新手引导
Flutter 使用 Overlay 实现全局