简介

我们知道Flutter中有两种Widget,分别是StatelessWidget和StatefulWidget,StatelessWidget中有一个build方法来创建对应的Widget,虽然StatefulWidget中没有对应的build方法,但是和StatefulWidget对应的State中也有同样的build方法。

这个build方法就是用来创建Widget的核心方法。

我们来看下build方法的定义:

Widget build(BuildContext context);

build方法传入一个BuildContext对象,返回一个Widget对象,也就是说这个BuildContext中包含了要创建的Widget的所有信息。这个BuildContext被称为是Widget的上下文构建环境。

那么BuildContext有什么特性呢?我们又该如何使用BuildContext呢?一起来看看吧。

BuildContext的本质

还记得flutter中的三颗树吗?

他们分别是Widgets树,Element树和Render树。其中Widgets树和Element树是一一对应的。而Render树和Element中的RenderObjectElement是一一对应的。

事实上BuildContext就是一个Element对象。怎么说呢?

我们先看下BuildContext的定义:

abstract class BuildContext {

    Widget get widget;
...
}

BuildContext是一个抽象类,我们再看一下Element类的定义:

abstract class Element extends DiagnosticableTree implements BuildContext {

可以看到,Element对象实现了BuildContext接口,而每一个BuildContext都有一个和其绑定的Widget对象。

经过复杂的关系传递运算,我们可以知道Element对象和Widget对象从代码层面来说,确实是一一对应的。

BuildContext和InheritedWidget

InheritedWidget是一种widget用来在tree中向下传递变动信息,在tree的子节点中,可以通过调用BuildContext.dependOnInheritedWidgetOfExactType在子节点中查找最近的父InheritedWidget,从而将当前的BuildContext绑定的widget和InheritedWidget建立绑定关系,从而在下次InheritedWidget发生变动的时候,会自动触发BuildContext绑定的widget的rebuild方法。

听起来好像很复杂的样子,但是实际上很简单,我们举个例子,首先我们需要定义一个Widget用来继承InheritedWidget:

class FrogColor extends InheritedWidget {
const FrogColor({
Key? key,
required this.color,
required Widget child,
}) : super(key: key, child: child); final Color color; static FrogColor of(BuildContext context) {
final FrogColor? result = context.dependOnInheritedWidgetOfExactType<FrogColor>();
assert(result != null, 'No FrogColor found in context');
return result!;
} @override
bool updateShouldNotify(FrogColor old) => color != old.color;
}

在这个方法中,我们需要定义一个of方法,这个该方法中,我们调用context.dependOnInheritedWidgetOfExactType方法,用来查找离BuildContext最近的FrogColor。

然后可以这样使用:

class MyPage extends StatelessWidget {
const MyPage({Key? key}) : super(key: key); @override
Widget build(BuildContext context) {
return Scaffold(
body: FrogColor(
color: Colors.green,
child: Builder(
builder: (BuildContext innerContext) {
return Text(
'Hello Frog',
style: TextStyle(color: FrogColor.of(innerContext).color),
);
},
),
),
);
}
}

我们的本意是希望child中的Text组件的style根据父widget中的FrogColor的color来进行变化。所以在子组件的style中调用了FrogColor.of(innerContext)方法,对InheritedWidget进行查找,同时建立绑定关系。

在BuildContext中,有两个查找并且进行绑定的方法,他们是:

InheritedWidget dependOnInheritedElement(InheritedElement ancestor, { Object aspect });

T? dependOnInheritedWidgetOfExactType<T extends InheritedWidget>({ Object? aspect });

两者的区别是,后者限定了查找的类型。

除了dependOn之外,BuildContext还提供了两个查找的方法:

InheritedElement? getElementForInheritedWidgetOfExactType<T extends InheritedWidget>();
T? findAncestorWidgetOfExactType<T extends Widget>();
T? findAncestorStateOfType<T extends State>();
T? findRootAncestorStateOfType<T extends State>();
T? findAncestorRenderObjectOfType<T extends RenderObject>();

他们和depend的区别是,他们不会建立依赖关系,只是单纯的进行查找。

BuildContext的层级关系

因为每个widget都有一个BuildContext,所以我们在使用的过程中一定要注意传入的BuildContext到底绑定的是哪个widget。

如下面的代码所示:

class MyPage extends StatelessWidget {
const MyPage({Key? key}) : super(key: key); @override
Widget build(BuildContext context) {
return Scaffold(
body: FrogColor(
color: Colors.green,
child: Builder(
builder: (BuildContext innerContext) {
return Text(
'Hello Frog',
style: TextStyle(color: FrogColor.of(innerContext).color),
);
},
),
),
);
}
}

在FrogColor的child中,我们创建了一个新的Builder,并提供了一个新的innerContext。

为什么要这样做呢?因为如果我们不创建子innnerContext的话,使用的context就是Scaffold的,这样FrogColor.of将会找不到要找的对象,从而报错。

所以我们在使用BuildContext的时候,一定要注意。

总结

BuildContext是构建Widget的基础,它也提供了一些非常有用的查找和绑定的功能,希望能对大家有所帮助。

更多内容请参考 http://www.flydean.com/04-flutter-buildcontext/

最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!

欢迎关注我的公众号:「程序那些事」,懂技术,更懂你!

flutter系列之:构建Widget的上下文环境BuildContext详解的更多相关文章

  1. 转载 CSS3 经典教程系列:CSS3 盒阴影(box-shadow)详解

    目标大纲 文章转载 CSS3 经典教程系列:CSS3 盒阴影(box-shadow)详解 IE中CSS-filter滤镜小知识大全 CSS实现跨浏览器兼容性的盒阴影效果

  2. Spark Streaming揭秘 Day28 在集成开发环境中详解Spark Streaming的运行日志内幕

    Spark Streaming揭秘 Day28 在集成开发环境中详解Spark Streaming的运行日志内幕 今天会逐行解析一下SparkStreaming运行的日志,运行的是WordCountO ...

  3. Nginx+Tomcat的服务器端环境配置详解

    这篇文章主要介绍了Nginx+Tomcat的服务器端环境配置详解,包括Nginx与Tomcat的监控开启方法,需要的朋友可以参考下 Nginx+tomcat是目前主流的Javaweb架构,如何让ngi ...

  4. Windows GTK+ 环境搭建(详解)

    来源:http://blog.sina.com.cn/s/blog_a6fb6cc901017ygy.html Windows GTK+ 环境搭建 最近要做界面的一些东西,但是对微软提供的类库MFC不 ...

  5. 单元测试系列之十一:Jmockit之mock特性详解

    本文是Jmockit学习过程中,根据官网所列的工具特性进行解读. 1.调用次数约束(Invocation count constraints) 可以通过调用计数约束来指定预期和/或允许匹配给定期望的调 ...

  6. MySQL高可用方案-PXC(Percona XtraDB Cluster)环境部署详解

    MySQL高可用方案-PXC(Percona XtraDB Cluster)环境部署详解 Percona XtraDB Cluster简称PXC.Percona Xtradb Cluster的实现是在 ...

  7. net core体系-web应用程序-4net core2.0大白话带你入门-5asp.net core环境变量详解

    asp.net core环境变量详解   环境变量详解 Windows操作系统的环境变量在哪设置应该都知道了. Linux(centos版本)的环境变量在/etc/profile里面进行设置.用户级的 ...

  8. Maya 常用环境变量详解

    Maya 常用环境变量详解 前言: Maya 的环境变量让用户可以很方便的自定义 Maya 的功能. 在 Maya 的 Help 帮助文档中有专门的一个章节< Environment Varia ...

  9. Python环境搭建详解(Window平台)

    前言 Python,是一种面向对象的解释型计算机程序设计语言,是纯粹的自由软件,Python语法简洁清晰,特色是强制用空白符作为语句缩进,具有丰富和强大的库,它常被称为胶水语言. Python是一种解 ...

随机推荐

  1. Eureka入门

    一个Eureka中分为eureka server和eureka client.其中eureka server是作为服务的注册与发现中心.eureka client既可以作为服务的生产者,又可以作为服务 ...

  2. 关于 GIN 的路由树

    GIN 是一个 golang 常用的 Web 框架,它对 API 比较友好,源码注释也很明确明确,使用起来快速灵活,还有极高的容错率.标题中的路由我们可以简单理解为在浏览器中输入的页面地址,而&quo ...

  3. Feign通过自定义注解实现路径的转义

    本文主要讲解如果通过注解实现对路由中的路径进行自定义编码 背景 近期由于项目中需要,所以需要通过Feign封装一个对Harbor操作的sdk信息. 在调用的过程中发现,当请求参数中带有"/& ...

  4. 从Mpx资源构建优化看splitChunks代码分割

    背景 MPX是滴滴出品的一款增强型小程序跨端框架,其核心是对原生小程序功能的增强.具体的使用不是本文讨论的范畴,想了解更多可以去官网了解更多. 回到正题,使用MPX开发小程序有一段时间了,该框架对不同 ...

  5. 【问题解决】Alpine镜像中执行jstack、arthas等命令提示Unable to get pid of LinuxThreads manager thread

    问题现象 最近在处理项目上问题发现之前同事构建的AlpineLinux的镜像不能执行jstack等JDK命令,报错如下. Unable to get pid of LinuxThreads manag ...

  6. Pytorch从0开始实现YOLO V3指南 part3——实现网络前向传播

    本节翻译自:https://blog.paperspace.com/how-to-implement-a-yolo-v3-object-detector-from-scratch-in-pytorch ...

  7. ReentrantLock 公平锁源码 第0篇

    ReentrantLock 0 关于ReentrantLock的文章其实写过的,但当时写的感觉不是太好,就给删了,那为啥又要再写一遍呢 最近闲着没事想自己写个锁,然后整了几天出来后不是跑丢线程就是和没 ...

  8. CMU15445 (Fall 2019) 之 Project#4 - Logging & Recovery 详解

    前言 这是 Fall 2019 的最后一个实验,要求我们实现预写式日志.系统恢复和存档点功能,这三个功能分别对应三个类 LogManager.LogRecovery 和 CheckpointManag ...

  9. Solution -「ABC 217」题解

    D - Cutting Woods 记录每一个切割点,每次求前驱后驱就好了,注意简单判断一下开闭区间. 考场上采用的 FHQ_Treap 无脑莽. #include <cstdio> #i ...

  10. 20220722-Java可变参数

    Java可变参数总结 来源:B站韩顺平老师的Java入门教学 代码示例如下: public void f(String str,int... nums){ 方法体; } 代码示例如下: public ...