在正式开始阅读本文之前,希望读者阅读下博主的 Flutter之BuilderContext和Widget关系浅析 Fultter之Element和Widget对应关系 这两篇博文,这是本篇博文的理论知识储备。通过这两篇博文你可以了解到:
1、Widget和Element的对应关系
2、Widget和Element的初始化时机
3、Flutter的BuildContext到底是什么玩意
4、StatefulWidget的state跟StatefulElement之间的联系

本文的的涉及到的代码demo, 点此查看

GlobalKey详解

GlobalKey的作用

先说结论,后文会分析此结论的由来: 每个 Widget 都对应一个 Element ,我们可以直接对 Widget 进行操作,但是无法直接操作 Widget 对应的 Element 。而 GlobalKey 就是那把直接访问 Element 的钥匙。通过 GlobalKey 可以获取到 Widget 对应的 Element ,比如获取 StatelessElement StatefulElement . 比如如果获取到了 StatefullElement ,那么我们就可以获取 StatefulElement State 对象,拿到后我们就可以进行一些相应的操作。

/// An [Element] that uses a [StatefulWidget] as its configuration.
class StatefulElement extends ComponentElement {
  @override
  Widget build() => state.build(this);
  State<StatefulWidget> get state => _state!;
  State<StatefulWidget>? _state;

下面我们就以Form表单为例来分析GlobalKey为什么可以获取Widget对应的Element

GlobalKey实战举例

登录肯定要有输入用户名和密码的输入框,在Flutter中我们只用Form表单+TextFormField的形式加以实现。现在就来讲讲FormTextFormField的简单使用,demo中登录界面如下:
在这里插入图片描述
然后我们在不输入任何字符的情况下点击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 的状态类,通过StatefulWidgetcreateState方法创建:

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

上文中为什么通过GlobalKey.currentState就可以获取到FormState呢?二者是怎么关联起来的呢?现在就来一探究竟。

先来看看GlobalKeycurrentState方法的具体实现:

  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的作用就是:*持有当前WidgetElement对象,因此通过GlobalKey对象可以获取到当前StatefulWidgetStatefullElement,在通过StatefullElement获取State状态对象,从而操控State的相关方法。比如FormState的validate()方法进行非空校验

事实上我们还可以使用Form.of(context)方法也可以获到FormState对象,然后调用validate方法完成TextFormField的非空校验,其中原理,详细解析见Flutter之实战InheritedWidget详解

本篇博文更新于2021年12月7号。

博主打算通过登录功能来总结一下Flutter的相关知识点。为什么选择登陆功能呢?因为登录功能逻辑简单,很好抽象,功能也很普遍,这也是博主以此为突破口写android MVC和MVP探讨的原因。本系列应该不长,初步估计也就三篇左右,通过层层递进,慢慢地会勾勒出一个完整的登陆功能的demo,demo的源码点此可得。俗话说站在巨人的肩膀上成长的更快,当然这个俗话是我瞎篇水字数的,本系列博文的重要参考资料...
Flutter是借鉴React的开发思想实现的,在子组件的插槽上,React有this.props.children,Vue有<slot></slot>。 当然Flutter也有类似的Widget,那就是Navigator,不过是以router的形式实现(像<router></router>???)。 Navigator的使用无非3个属性 initialRoute: 初始路由 onGenerateRoute: 匹配路由 onUnknownRoute: 404 在实现层面 首先:Navigator的高度为infinity。如果直接父级非最上级也是infinity会
在介绍Flutter布局之前,我们得先了解Flutter中的一些布局相关的特性。boxconstraints有人也翻译为盒约束、箱约束,我个人还是觉得边界约束可能更直观一些。Flutter中的边界约束,是指widget可以按照指定限定条件,来决定自身如何占用布局空间。Flutter借鉴了很多React相关的东西,包括一些布局思想,但是它自身没有抽离出布局样式,而是用不同的widget去实现不同的布局,将样式嵌入widget中,用户可以像搭积木一样写布局,写法上跟React很像,只不过没了样式的设定。这样做的好处,我觉得可能是为了统一的渲染。加入样式,会让布局复杂不少,在渲染层面会降低很多性能。
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. GlobalKey只能单独使用不能重复使用,不然会报Duplicate GlobalKey detected in widget tree.当然你可以定义多个GlobalKey。当我们需要找到一个数据时,我们给这个组件定义一个GlobalKey。 _globalKey.currentState:获取所定义的State状态 _globalKey.currentWidget:获取所定义的
flutter有三棵树:widgetTree,elementTree,renderObjectTree,widget包含了基本的配置信息,element决定要不要重新创建renderObject,而renderObject则负责实际的渲染工作。我们来看一个例子,代码如下: main.dart
1. 什么是key 您可以使用key来控制框架将在widget重建时与哪些其他widget匹配。默认情况下,框架根据它们的runtimeType和它们的显示顺序来匹配。使用key时,框架要求两个widget具有相同的key和runtimeType。 Widget 更新机制 下面来来看Widget的源码。 @immutable abstract class Widget extends Diag...
Webview not displayed because it is too large to fit into a software layer (or drawing cache) 微信开放标签 OpenSDk 无法打开APP或者WXEntryActivity无响应 解决方法 Android Studio 报错:Cause: unable to find valid certification path to requested target