题记
—— 执剑天涯,从你的点滴积累开始,所及之处,必精益求精,即是折腾每一天。

** 你可能需要
CSDN 网易云课堂教程
掘金 EDU学院教程
知乎 Flutter系列文章

本文章将讲述 Widget 、Element、RenderObject 三者的关系 以及各自的角色 Flutter三颗树的关系,以及描述 Context 什么情况 下可使用,以及通过 Element 获取获取对应的Widget在手机屏幕显示中的位置与大小


在 Flutter 中通过构建一系列的 Widget就可建立起一个应用,一系列的 Widget 通过一写的结构排列,构成 Widgets 树,类似 HTML 中的 DOM树。

在Flutter项目开发中,通过Widget构建各种显示UI效果,最终显示在手机屏幕上。

在Flutter图像绘制原理深入分析一节中 有分析图像的显示原理,在这里 我们开发使用的是构建 Widget ,Widget 这个角色是Flutter SDK 封装好的一些接口以便开发者便捷开发应用程序,实际绘制到手机屏幕上时是通过 RenderObject 这个角色来处理的,也就是 一个 Widget如Text要显示出来,要经历 Widget --> Element --> RenderObject 这三个阶段的转换。

1 Widget 、Element、renderObject角色分析

在 Flutter 的 Engine 层向 Dart 层的暴露了 Canvas, PictureRecorder 等接口,利用这些接口可以绘制自己想要的图像,通过 Canvas, PictureRecorder 等接口来绘制图像,这操作有点复杂,不利于便捷开发,所以一般常使用 Widget。

如下代码 一个 线性布局 Column 中排列了两个 文本 Text :

   Widget buildColumnWidget(){return Column(children: [Text("张三"),Text("李四"),],);}

实际项目中的显示效果如下图所示,为两个文本在竖直方向线性排列:

在这里构建了三个Widget,Column 与两个Text,它们的Widgets树形结构排列如下:

Widget的构建相当于是构建一定的配置信息,或者说是 Widget 的组合构建,相当于是将封装的一些特定的绘制指令进行组合。

组合好的Widget在程序执行到build方法时,会通过 createRenderObject 方法来创建对应的renderObject渲染对象。

一个图像要绘制出来,首先要进行测量计算(位置与大小),然后再根据测量计算的结果进行排版(layout),最后再进行绘制(Paint),这整一个操作过程是通过 renderObject对象来实现的,也就是说renderObject是最终真正的渲染对象。

renderObject对象第一步进行的计算数据的基础配制是在 Widget中构建的,所以需要从Widget中获取这些数据,renderObject对象的这一系列操作也需要一个载体,所以就有了 Element。

每一个 Widget都包含者绘制图像的配置信息,每一个配置信息都需要对应的一个renderObject对象来实现操作,所以有Widgets树,就也有renderObjects树,widget与renderObject之间需要 Element来协调配合,所以也有了 Element树。

如在上图 Widget树,当Column与Text被构建时,同时当前的 StatelessWidget或者是StatefulWidget中通过Widget.createElement方法来创建Elemen,框架层通过调用mount方法来将新创建的Element添加到给定父级中给定槽点的树上,所以对应着就构建了第二颗树如下图所示:

同时函数mount被调用的时候,框架层会调用RenderObjectWidget.createRenderObject()来实例化RenderObject,此时对应的第三颗树也就形成,如下:

2 通过 RenderObject 来获取手机屏幕上显示的Widget的位置与大小

Element 负责协调 Widget 与 renderObject,Element 同时持有 Widget 和 RenderObject,Element存放Widget上下文, Element 也就是我们在开发中通常使用到的 context,通过context 可以获取 Widget树中的信息,也可以获取对应的 renderObject中的信息。

我们在调用build时候的入参BuildContex其实返回的就是Element,在实际开发中,通常也会使用到 context,实际上context的返回也是element实例,如下

BuildContext get context => _element;

所以在实际项目开发中,在StatefulWidget的initState方法中,是不可使用 context ,因为此时的StatefulWidget对应的Element(也就是BuildContext)才刚刚创建,还没有形成绑定关系,也没有与对应的RenderObject绑定起来,所以不能使用。

同理在 方法 dispose中,StatefulWidget 与 Element 、RenderObject已解绑,所以也不能使用。

只有在绑定期间才可使用,在绑定与解绑都会回调生命周期方法 didChangeDependencies,所以可以在didChangeDependencies这个方法中使用 context做一些相关的操作,代码如下:

  @overridevoid didChangeDependencies() {super.didChangeDependencies();///是否是路由栈中的第一个页面bool isFirst = ModalRoute.of(context).isFirst;///当前手机屏幕上显示的是否是这个页面Widgetbool isCurrent = ModalRoute.of(context).isCurrent;///当前Widget是否是活跃可用的///当调用 pop 或者是关闭当前Widget时 isActive 为falsebool isActive = ModalRoute.of(context).isActive;if(isActive){///页面 活跃状态}else{///页面将要解绑}

所以在实际项目开发中,可以为每一个 Widget 绑定一个GlobalKey,通过 GlobalKey来获取对应的Element(BuildContext),然后通过Element来获取对应的RenderObject,从而获取这个Widget 在手机 屏幕上对应的位置与大小 信息,代码如下:

///第一步 创建 GlobalKey
GlobalKey globalKey = GlobalKey();///第二步在 对应的Widget 引用 ,如这里的Text
Text('张三',key:globalKey);///第三步 通过 globalKey 来获取 对应的Element(BuildContext) BuildContext stackContext = globalKey.currentContext;///第四步 获取对应的 RenderObject///RenderObject是抽象的,它的一些基础信息封装在子类RenderBox中RenderBox renderBox = stackContext.findRenderObject();
///然后通过 RenderBox 来获取对应的Text在手机屏幕上显示的位置 与大小 信息///相对于全局的位置Offset offset = renderBox.localToGlobal(Offset.zero);///获取指定的Widget的大小 信息Size size = renderBox.paintBounds.size;

完毕

Flutter中Widget 、Element、RenderObject角色深入分析相关推荐

  1. Flutter与JS的双向调用、Flutter中Widget与Html混合加载

    题记 -- 执剑天涯,从你的点滴积累开始,所及之处,必精益求精. Flutter是谷歌推出的最新的移动开发框架. [x1]微信公众号的每日提醒 随时随记 每日积累 随心而过 [x2]各种系列的视频教程 ...

  2. 初识Flutter中的Layer

    初识Flutter中的Layer 开篇 接触Flutter开发一段时间后发现自己对Flutter渲染流程重要的一环Layer的认知比较少,虽然Flutter对Widget的封装非常全面了开发者基本上只 ...

  3. element中有多个合计_深入理解 Flutter 中的 Widget, Element, RenderObject

    这篇文章基于 Flutter stable v1.7 总结下 Flutter 当前的 UI 系统以及相关的概念, 在最后会通过自己组合一个 Gradient Button 按钮的方式来熟悉 Flutt ...

  4. Flutter中State深入分析理解

    题记 -- 执剑天涯,从你的点滴积累开始,所及之处,必精益求精,即是折腾每一天. ** 你可能需要 CSDN 网易云课堂教程 掘金 EDU学院教程 知乎 Flutter系列文章 本文将从源码的角度讲述 ...

  5. 学 Flutter 不理解 Widget/Element/Render 三棵树?啥也不是!

    一.导语 Hi,大家好,这里是承香墨影! Flutter 是 Google 发布的跨平台 UI 框架,而其中与 UI 相关的,最重要的就是 Widget & Element & Ren ...

  6. Flutter中如何利用StreamBuilder和BLoC来控制Widget状态

    参考文章:Reactive Programming - Streams - BLoC (为了便于阅读,略去了原文中的一些跟StreamBuilder和Bloc无关的拓展概念,比如RxDart.Demo ...

  7. Flutter 中 stateless 和 stateful widget 的区别[Flutter专题60]

    Flutter 中 stateless 和 stateful widget 的区别 介绍 要在 Flutter 中构建任何应用程序,我们必须创建一个小部件类,它是 Flutter 应用程序的构建块.F ...

  8. 如何在 Flutter 中禁用默认的 Widget 飞溅效果

    如何在 Flutter 中禁用默认的 Widget 飞溅效果 默认情况下,许多 Flutter Material Design 小部件在被选中时会显示飞溅效果. 这适用于IconButton,InkW ...

  9. 给Flutter中的Widget设置透明度

    给Flutter中的Widget设置透明度 在项目开发中,需要经常用到透明度:比如在app中弹出一个提示框,这个时候的提示框就需要上下左右离边距有一定的距离,然后背景色舍黑色,需要设置透明度为0.4: ...

最新文章

  1. c#_可扩展标记语言XML
  2. linux shell脚本 传参,在bash shell脚本中传播所有参数
  3. Visual studio那些破事。。。(生成静态库、生成动态库、引用静态库、引用动态库)
  4. respect labor
  5. 微软对外开放更多软件技底层代码术文档
  6. php连接mysql地址_PHP连接mysql
  7. 查看远端的端口是否通畅3个简单实用案例
  8. C# 通过DirectInput 实现手柄操控
  9. 洞察药监局数据,挖掘万亿价值
  10. web项目接入指纹识别+识别过程信息推送
  11. 2.10 lnmp架构_慢查询 MySQL路由器 MHA高可用
  12. GitHub简介、fork、pull和clone、快速起步
  13. SQL group by和count
  14. 抖音蓝V如何认证,蓝V号与普通号的区别?
  15. 使用oracle开发的配置
  16. matlab中scr,基于matlab生成的scr文件,实现autocad曲线绘制,代码问题
  17. STM32通定时器时间设置步骤和计算公式方法寄存器值
  18. oracle 的lag,oracle分析函数lag
  19. 网络安全(一) 了解什么是黑客
  20. happens-before规则,是什么?怎么理解?有哪些规则?

热门文章

  1. FaceBoxes—官方开源CPU实时高精度人脸检测器
  2. Oracle PCTfree assm,Oracle 12C LMT ASSM 完美测试
  3. 【TensorFlow】TensorFlow函数精讲之 tf.nn.relu()
  4. 《Python编程从入门到实践》记录之input()函数
  5. wordpress安装到虚拟服务器,将WordPress安装在虚拟主机二级目录的方法
  6. VGG和GoogLeNet inception
  7. 深度学习(四十七)DSD正则化训练方法
  8. clion windows安装
  9. vector与array之间转换,向量与数据之间转换
  10. ros::spin() 和 ros::spinOnce()