Flutter中的BuildContext、Element、Key和RenderObject

学习Flutter不仅仅是学各Widget的使用,能堆叠出UI就行了,要多去学习底层的一些实现原理,尽量做到知其所以然。这也是区分程序员等级的一个参考指标。

在学习Flutter过程中,对BuildContext、Key、Element、RenderObject不是很了解,搜索了一下,觉得有些博客写的还是不错的,主要是了解Flutter视图树的构建过程,希望大家都能多去看看


BuildContext

Flutter | 深入理解BuildContext

文中原文:

在Flutter中,Everything is Widget,我们通过构造函数嵌套Widget来编写UI界面。实际上,Widget并不是真正要显示在屏幕上的东西,只是一个配置信息,它永远是immutable的,并且可以在多处重复使用。那真正显示在屏幕上的视图树是什么呢?Element Tree!

这里可以知道,我们编写的Widget都会调用createElement()方法去生成对应的Element,而这个Element就实现了BuildContext接口,官方说明:

BuildContextobjects are actually Element objects. The BuildContextinterface is used to discourage direct manipulation of Element objects.
BuildContext对象实际上就是Element对象,BuildContext 接口用于阻止对 Element 对象的直接操作。

Element对象中有一个RenderObject对象,多个Element对象的RenderObject对象组成RenderObject树,最终渲染到屏幕上:
在这里插入图片描述

视图树装载过程

StatelessWidget

  • 首先它会调用StatelessWidget的 createElement 方法,并根据这个widget生成StatelesseElement对象。
  • 将这个StatelesseElement对象挂载到element树上。
  • StatelesseElement对象调用widget的build方法,并将element自身作为BuildContext传入。

StatefulWidget

  • 首先同样也是调用StatefulWidget的 createElement方法,并根据这个widget生成StatefulElement对象,并保留widget引用。
  • 将这个StatefulElement挂载到Element树上。
  • 根据widget的 createState 方法创建State。
  • StatefulElement对象调用state的build方法,并将element自身作为BuildContext传入。

所以我们在build函数中所使用的context,正是当前widget所创建的Element对象。

在官网的另一份介绍中(暂时忘了链接了。。。):

A BuildContext object is a handle to the location of a widget in your app’s widget tree. Each widget has its own BuildContext, which becomes the parent of the widget returned by the StatelessWidget.build or State.build function. This means the _buildTextComposer() method can access the BuildContext object from its encapsulating State object; you don’t need to pass the context to the method explicitly.

大致意思是,一个BuildContext对象是一个Widget对象在Widget树中位置的句柄(我的理解就是标记的意思)。
每个Widget对象都有自己的BuildContext,是StatelessWidget.build方法或者State.build方法返回的Widget对象的父类对象,由于可以从State对象中获取到BuildContext对象,所以通常不需要显示的将Context对象传递到Widget的build方法里。

其实该文主要讲了Build Context的来源,大致介绍了Flutter视图树的创建过程,介绍的比较简单,如果想深入了解,这里还有其他的几篇文章可以参考,

原文介绍如下:

当我们在 build 函数中使用Navigator.of(context)的时候,这个context实际上是通过 MyApp 这个widget创建出来的Element对象,而of方法向上寻找祖先节点的时候(MyApp的祖先节点)并不存在MaterialApp,也就没有它所提供的Navigator。
所以当我们把Scaffold部分拆成另外一个widget的时候,我们在FirstPage的build函数中,获得了FirstPage的BuildContext,然后向上寻找发现了MaterialApp,并找到它提供的Navigator,于是就可以愉快进行页面跳转了

其实除了把home部分单独成一个Widget外,还可以使用Builder来解决context不对的问题


Key

Flutter | 深入浅出 Key

介绍Key要从Widget的更新机制开始说起,在Widget更新的时候,会调用canUpdate(Widget oldWidget, Widget newWidget)方法来对比前后两个Widget对象,部分源码如下:

@immutable
abstract class Widget extends DiagnosticableTree {
  const Widget({ this.key });
  final Key key;
  ···
  static bool canUpdate(Widget oldWidget, Widget newWidget) {
    return oldWidget.runtimeType == newWidget.runtimeType
        && oldWidget.key == newWidget.key;
  }
}

何时使用密钥 - Flutter小部件 101 第四集中,介绍Key对更新Widget的影响,视频中的原文:

Keys preserve state when widgets move around in your widget tree.
They can be used to preserve the user’s scroll location, or keeping state when modifying a collection.

视频中有三个部分:

When to use keys?

如果我们的一个集合中的整个widget子树都是stateless的,那么我们不需要使用key;
但是如果在添加、删除、或者重新排序一个widget集合,且这个widget集合里的widget具有相同的类型和持有状态state的时候,这时候就需要使用key了。

Where to put them in your widget tree?

答案是:在需要保存状态的Widget子树的顶部来声明key

Flutter的element到widget的匹配算法不是对比第一个StatefulWidget,而是对比某一个层级的Widget,

具体可以参考Flutter | 深入浅出 Key

Which key is right for you?

在这里插入图片描述

关于Key的种类有多种,在上文中也列出来了,后面等使用到了再多做介绍。。。


RenderObject和RenderBox

flutter-in-action的第14章,Flutter核心原理

Flutter UI系统
Element和BuildContext
RenderObject和RenderBox
Flutter从启动到显示

等多使用了RenderBox之后再来介绍吧。。。


Flutter Widgets101

⭐️最后,非常推荐看官方的视频Flutter Widgets101,可以直接看英文字幕,中文的字幕翻译不是很好

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值