首页 > 其他分享 >flutter系列之:构建Widget的上下文环境BuildContext详解

flutter系列之:构建Widget的上下文环境BuildContext详解

时间:2022-08-26 14:16:52浏览次数:89  
标签:Widget color BuildContext FrogColor build key flutter

目录

简介

我们知道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/

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

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

标签:Widget,color,BuildContext,FrogColor,build,key,flutter
From: https://www.cnblogs.com/flydean/p/16627338.html

相关文章

  • Qt QWidget绘制圆角注意事项
    1、产生黑边painter.setPen(Qt::NoPen);//不设置画笔即可 2、背景不透明this->setAttribute(Qt::WA_TranslucentBackground,true); 3、大致代码this->setA......
  • 窗口部件-基础窗口部件 QWidget
    1基础窗口部件QWidgetQWidget类是所有用户界面对象的基类,被称为基础窗口部件.不多废话直接看代码main.cpp如下#include<QtWidgets>intmain(intargc,char......
  • Flutter 循环创建输入框 TextField
    需求:根据接口返回的数据生成列表,列表内含有可编辑的字段 先初始化一个 TextEditingController集合Map<Object,TextEditingController>_numberControllers=......
  • flutter系列之:用来管理复杂状态的State详解
    目录简介StatefuWidget和StateState的生命周期总结简介Flutter的基础是widget,根据是否需要跟用户进行交互,widget则可以分为StatelessWidget和StatefulWidget。Stateless......
  • qt实现父界面中多子界面间的切换---stackWidget
    qt实现父界面中多子界面间的切换---stackWidget1.创建新项目2.项目命名3.起类名起类名之前的步骤可直接next即可。4.打开ui5.拖入控件6.添加新页该步可跳过,当......
  • ArcGIS API for JavaScript Editor Widget 选中多个要素不显示名称
    背景 最近升级时遇到了之前碰到的问题,但是忘记解决方法了。又重新对比了旧代码才找到,所以记录下。FeatureLayer的构建方式不是url,而是用的source环境 Vu......
  • Live2d Widget
    写在最前最早的时候看别人的博客很多都有一个可爱的看板娘,然后就找了教程给自己也整了一个。因为找到的教程都是稂莠不齐的,原作者自己说的也略显含糊(其实是我自己看不懂)。......
  • 向QtableWidget中添加自定义widget崩溃异常: 0xC0000005
    1.问题描述想给QTableWidget添加QCheckBox,代码如下,tableWidget->setCellWidget老是崩溃(0x0F954E63(qwindows.dll)处(位于QStockView.exe中)引发的异常:0xC0000005: ),......
  • flutter 效果实现 —— 全局点击空白处隐藏键盘
    为什么要实现点击空白处隐藏键盘?因为这是iOS平台的默认行为,Android平台由于其弹出的键盘右上角默认带有关闭键盘的按钮,所以点击空白处不会隐藏键盘。单个页面,可以这样......
  • flutter 效果实现 —— sliver 固定
    效果:说明:绿色块在向上滑动,距离顶部103的高度(即AppBar下面)时固定代码:classPinnedSliverPageextendsStatefulWidget{constPinnedSliverPage({Key?key}):......