Flutter中Widget 、Element、RenderObject角色深入分析
题记
—— 执剑天涯,从你的点滴积累开始,所及之处,必精益求精,即是折腾每一天。
** | 你可能需要 |
---|---|
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角色深入分析相关推荐
- Flutter与JS的双向调用、Flutter中Widget与Html混合加载
题记 -- 执剑天涯,从你的点滴积累开始,所及之处,必精益求精. Flutter是谷歌推出的最新的移动开发框架. [x1]微信公众号的每日提醒 随时随记 每日积累 随心而过 [x2]各种系列的视频教程 ...
- 初识Flutter中的Layer
初识Flutter中的Layer 开篇 接触Flutter开发一段时间后发现自己对Flutter渲染流程重要的一环Layer的认知比较少,虽然Flutter对Widget的封装非常全面了开发者基本上只 ...
- element中有多个合计_深入理解 Flutter 中的 Widget, Element, RenderObject
这篇文章基于 Flutter stable v1.7 总结下 Flutter 当前的 UI 系统以及相关的概念, 在最后会通过自己组合一个 Gradient Button 按钮的方式来熟悉 Flutt ...
- Flutter中State深入分析理解
题记 -- 执剑天涯,从你的点滴积累开始,所及之处,必精益求精,即是折腾每一天. ** 你可能需要 CSDN 网易云课堂教程 掘金 EDU学院教程 知乎 Flutter系列文章 本文将从源码的角度讲述 ...
- 学 Flutter 不理解 Widget/Element/Render 三棵树?啥也不是!
一.导语 Hi,大家好,这里是承香墨影! Flutter 是 Google 发布的跨平台 UI 框架,而其中与 UI 相关的,最重要的就是 Widget & Element & Ren ...
- Flutter中如何利用StreamBuilder和BLoC来控制Widget状态
参考文章:Reactive Programming - Streams - BLoC (为了便于阅读,略去了原文中的一些跟StreamBuilder和Bloc无关的拓展概念,比如RxDart.Demo ...
- Flutter 中 stateless 和 stateful widget 的区别[Flutter专题60]
Flutter 中 stateless 和 stateful widget 的区别 介绍 要在 Flutter 中构建任何应用程序,我们必须创建一个小部件类,它是 Flutter 应用程序的构建块.F ...
- 如何在 Flutter 中禁用默认的 Widget 飞溅效果
如何在 Flutter 中禁用默认的 Widget 飞溅效果 默认情况下,许多 Flutter Material Design 小部件在被选中时会显示飞溅效果. 这适用于IconButton,InkW ...
- 给Flutter中的Widget设置透明度
给Flutter中的Widget设置透明度 在项目开发中,需要经常用到透明度:比如在app中弹出一个提示框,这个时候的提示框就需要上下左右离边距有一定的距离,然后背景色舍黑色,需要设置透明度为0.4: ...
最新文章
- c#_可扩展标记语言XML
- linux shell脚本 传参,在bash shell脚本中传播所有参数
- Visual studio那些破事。。。(生成静态库、生成动态库、引用静态库、引用动态库)
- respect labor
- 微软对外开放更多软件技底层代码术文档
- php连接mysql地址_PHP连接mysql
- 查看远端的端口是否通畅3个简单实用案例
- C# 通过DirectInput 实现手柄操控
- 洞察药监局数据,挖掘万亿价值
- web项目接入指纹识别+识别过程信息推送
- 2.10 lnmp架构_慢查询 MySQL路由器 MHA高可用
- GitHub简介、fork、pull和clone、快速起步
- SQL group by和count
- 抖音蓝V如何认证,蓝V号与普通号的区别?
- 使用oracle开发的配置
- matlab中scr,基于matlab生成的scr文件,实现autocad曲线绘制,代码问题
- STM32通定时器时间设置步骤和计算公式方法寄存器值
- oracle 的lag,oracle分析函数lag
- 网络安全(一) 了解什么是黑客
- happens-before规则,是什么?怎么理解?有哪些规则?
热门文章
- FaceBoxes—官方开源CPU实时高精度人脸检测器
- Oracle PCTfree assm,Oracle 12C LMT ASSM 完美测试
- 【TensorFlow】TensorFlow函数精讲之 tf.nn.relu()
- 《Python编程从入门到实践》记录之input()函数
- wordpress安装到虚拟服务器,将WordPress安装在虚拟主机二级目录的方法
- VGG和GoogLeNet inception
- 深度学习(四十七)DSD正则化训练方法
- clion windows安装
- vector与array之间转换,向量与数据之间转换
- ros::spin() 和 ros::spinOnce()