Flutter | 由Builder Widget而引发的思考

2022-02-09 13:59:50 浏览数 (1)

概要

本篇主要是我实际学习中遇到的一个问题,从而引发的一些思考,从本篇你将学到如下:

  • Builder 神奇却又简单的背后缘由
  • BuildContext 的真实理解
  • widgetelement 的关系,及流程分析

背景

关于 Builder 这个widget,我想大家都是通过报错才发现的有这个widget的。

比如 From.of(context) ,为什么null指针(Dart新特性)了,Navigator.maybePop(context) 怎么异常了,诸如此类需要 context 传入的地方。

于是我举一个最简单的例子如下:

详细解释如图所示。使用Form来验证我们的输入框是否输入合格。

作为一个Flutter新手,肯定会好奇,我为啥null了呢,然后google一搜,就有人建议你使用 Builder,然后我们就会将代码改为以下方式:

欧耶,好啦,就这么简单啊。

等等,好像有什么地方不对,作为一个由良知,有道德,遵纪守法,爱国,不掉头发的 新时代无产阶级 干饭人,疯狂套用似乎不符合我的气质,我决定深入细节,看看你这葫芦里卖的什么药。

Builder 是什么?

官方解释:

一个无状态实用程序小部件,其[build]方法使用其[builder]回调创建小部件的子级。

源码如下

代码语言:javascript复制
class Builder extends StatelessWidget {

  const Builder({
    Key? key,
    required this.builder,
  }) : assert(builder != null),
       super(key: key);
       
  @override
  Widget build(BuildContext context) => builder(context);
}

当我看过Builder的源码,我从没感觉自己如此机智且聪明,是个开发者都能看懂。很简单,就尼玛的一个接口回调,这是不是随手都能写一个出来。

缘由

那为什么我自己的context不行呢?

让我们先去看看 Form.of 方法,当然其他of的方法也类似。

代码语言:javascript复制
static FormState? of(BuildContext context) {
  //获取给定类型为T的最近的小部件,该类型必须是具体的[InheritedWidget]子类的类型,并向该小部件注册该构建上下文,以便在该小部件发生更改时(或引入该类型的新小部件时,或窗口小部件消失),将重新构建此构建上下文,以便它可以从该窗口小部件获取新值
  final _FormScope? scope = context.dependOnInheritedWidgetOfExactType<_FormScope>();
  return scope?._formState;
}

咳咳,简单理解 dependOnInheritedWidgetOfExactType

这个方法会根据我们传递进去的context,去从它的父级开始向上查询与当前 给定的类型匹配以及最近的这个widget,如果找到就返回,否则就抛异常。

然后 让我们将视角切换到最开始的截图,注意我圈出来的地方。

哦,我可真是个小菜瓜啊,我传递个根context进去,你让From.of() 怎么找,它的父Widget树向上怎么可能有FromState。

知道了缘由,甚至于你自己可以不用 Builder,自己写一个小组件也行,比如下面示例。

思考

但是到这里就结束了吗?如果对于本篇而言,的确是。但对我自己而言,却带来了更多疑问:

  • context 到底是干什么的?
  • build(context) 方法中的 BuildContext 是哪里来的?

Widget和Element的关系

我们常听说 Flutter有三棵树,也就是 Widget , ElementRenderObject ,我们主要关心前两者。

Widget 树,顾名思义,就是我们常用的组件,其仅仅相当于我们对 UI 元素的一个 配置

Element,是Widget 实际对应的对象。why?没懂,没错,其实我也没明白

0 人点赞