Flutter视图基础简介--Widget、Element、RenderObject
前言:Flutter官方文档里的一句话:you build your UI out of widgets(使用Flutter开发UI界面时,都是使用Widget),然而,Widget并不是我们真正看到的视图,背后究竟是什么?其实Flutter Framework提供了三种视图树,即:Widget Element RenderObject,只不过,我们使用Flutter开发界面时,通常只和widget打交道,就如前文中所展示的Materail风格或者Cupertino(IOS风格)的各种Widget,然而Flutter界面开发是一种响应式编程,并且Widget都是immutable的,那么,真正的渲染,刷新,布局这些问题是谁来处理呢?本文就来了解一下除了Widget,还有哪些基础类在背后支撑Widget的快速轻量渲染;
Widget部分:
Widget是用户界面的一部分,并且是不可变的(immutable)。Widget会被inflate到Element,并由Element管理底层渲染树。Widget本身没有可变状态(所有的字段必须是final)。如果想要把可变状态与Widget关联起来,可以使用StatefulWidget,StatefulWidget通过使用StatefulWidget.createState方法创建State对象,并将之扩充到Element以及合并到树中;
给定的Widget可以被包含在树中(零次或多次)。一个给定的Widget可以放置在树中多次,比如:多个TextWidget。每次将一个Widget放入树中时,它都会被扩充到一个Element中,这也意味着多次并入树中的Widget将会被多次扩充进对应的element。
Widget中的Key这个属性控制一个Widget如何替换树中的另一个Widget。如果两个Widget的runtimeType和key属性相等(==),则新的widget通过更新Element(即通过使用新的Widget调用Element.update)来替换旧的Widget。否则,如果两个Widget的runtimeType和key属性不相等,则旧的Element将从树中被移除,新的Widget将被扩充到一个新的Element中,这个新的Element将被插入树中。
这里主要涉及到Widget的更新和移除,插入等操作,在执行此操作前,会用Widget的两个属性:runtimeType和key来进行对比判断;
Element部分
Flutter创建Element的可见树,相对于Widget来说,是可变的,通常的Flutter界面开发中,我们不用直接操作Element,而是由框架层实现内部逻辑;就如一个UI视图树中,可能包含有多个TextWidget(Widget被使用多次),但是放在内部视图树的视角,这些TextWidget都是填充到一个个独立的Element中;
同样,我们先来看一下Element这个类中的属性:
property | Type | Desc | implement |
depth | int | 树根Element的深度必须大于0 |
int get depth => _depth;
|
dirty | bool | 如果Element已经被标注成需要重建,返回true |
bool get dirty => _dirty;
|
hashCode | int |
@overrideint get hashCode => _cachedHash;
|
|
owner | BuildOwner | 管理Element生命周期 |
@overrideBuildOwner get owner => _owner;
|
renderObject | RenderObject | 如果此对象是RenderObjectElement,则渲染对象是树中此位置处的对象。否则,这个getter将沿着树走下去,直到找到一个RenderObjectElement。 | |
size | Size | 省略 | 省略 |
slot | 省略 | 省略 | |
widget | Widget | 这个Element的配置信息 |
@overrideWidget get widget => _widget;
|
runtimeType |
Widget描述如何配置子树,但由于Widget是不可变的(immutable),因此可以使用相同的Widget同时配置多个子树。Element表示Widget配置树中的特定位置的实例。随着时间的推移,与给定Element关联的Widget可能随时会发生变化,例如,如果父Widget重建并为此位置创建新的Widget。Element构成一棵树。大多数Element都有一个唯一的子Element,但是一些Widget(例如RenderObjectElement的子类)可以有多个子Element。
Element具有以下生命周期:
- 框架层通过调用即将被用来作为Element的初始化配置信息的Widget的Widget.createElement方法来创建Element;
框架层通过调用mount方法来将新创建的Element添加到给定父级中给定槽点的树上。 mount方法负责将任何Widget扩充到Widget并根据需要调用attachRenderObject,以将任何关联的渲染对象附加到渲染树上。
此时,Element被视为“激活的”,并可能出现在屏幕上。 在某些情况下,父(Element)可能会更改用于配置此Element的Widget,例如因为父Element重新创建了新状态。发生这种情况时,框架层将调用新的Widget的update方法。新Widget将始终具有与旧Widget相同的runtimeType和key属性。如果父Element希望在树中的此位置更改Widget的runtimeType或key,可以通过unmounting(卸载)此Element并在此位置扩充新Widget来实现。
在某些时候,祖先Element可能会决定从树中移除该Element(或中间祖先Element),祖先Element自己通过调用deactivateChild来完成该操作。停用中间祖先将从渲染树中移除该Element的渲染对象,并将此Element添加到owner属性中的非活动元素列表中,从而让框架层调用deactivate方法作用在此Element上。 此时,该Element被视为“无效状态”,并且不会出现在屏幕上。一个Element可以保持”非活动"状态,直到当前动画帧结束。在动画帧结束时,任何仍处于非活动状态的Element都将被卸载。 如果Element被重新组合到树中(例如,因为它或其祖先之一有一个全局键(global key)被重用),框架层将从owner属性中的非活动Element列表中移除该Element,并调用该Element的activate方法,并重新附加Element的渲染对象到渲染树。 (此时,Element再次被视为“活动状态”并可能出现在屏幕上。) 如果Element在当前动画帧的末尾没有被重新组合到树中,则框架层将调用该元素的unmount方法。- 此时,该元素被视为“已停用”,并且将来不会并入树中。
由此我们可知:Element存放Widget上下文,通过遍历视图树,Element 同时持有 Widget 和 RenderObject;
RenderObject部分
RenderObjects有一个父级,并有一个名为parentData的插槽,其中父级RenderObject可以存储特定于子级的数据,例如子级位置。 RenderObject类也实现了基本的布局和绘制协议。但是,RenderObject类没有定义子模型(例如,节点是否有零个,一个或多个子节点)。它也没有定义坐标系(例如,子级是否位于笛卡尔坐标系,极坐标系等)或特定的布局协议(例如布局是宽度高度还是尺寸约束或者父级在子级布置之前还是之后设置子级的大小和位置等;或者确实是否允许子级读取他们父级的parentData插槽)。RenderBox子类引入布局系统使用笛卡尔坐标。
在大多数情况下,RenderObject本身的子类化过度,RenderBox将是一个更好的起点。但是,如果渲染对象不想使用笛卡尔坐标系,那么它应该直接从RenderObject继承。这允许它通过使用约束的新子类而不是使用BoxConstraints来定义自己的布局协议,并且可能使用全新的一组对象和值来表示输出的结果而不仅仅是一个Size。这种增加的灵活性的代价是无法依赖RenderBox的功能。例如,RenderBox实现了一个内在的尺寸调整协议,它允许您在没有完全铺设的情况下测量一个子级,以这样的方式,如果该子级改变了尺寸,父级将再次布置(考虑到子级的新尺寸)。这是一个微妙的和容易出错的功能。编写RenderBox的大多数方面也适用于编写RenderObject,因此推荐先阅读RenderBox的相关讨论。主要区别在于布局和命中测试,因为这些是RenderBox主要专注的方面。
Layout
布局协议从约束的子类开始。有关如何编写Constraints子类的更多信息,请参阅Constraints中的讨论。performLayout方法应该接受约束并应用它们。布局算法的输出是设置在对象上的字段,用于描述父对象布局的对象几何图形。例如,使用RenderBox的输出是RenderBox.size字段。如果父级指定parentUsesSize为true,则在调用子级布局时,此输出只能由父级读取。任何时候渲染对象上的任何变化都会影响该对象的布局,它应该调用markNeedsLayout。
转载请注明出处
From crash_coder linguowu linguowu0622@gamil.com
转载于:https://www.cnblogs.com/crashmaker/p/9123763.html
Flutter视图基础简介--Widget、Element、RenderObject相关推荐
- 学 Flutter 不理解 Widget/Element/Render 三棵树?啥也不是!
一.导语 Hi,大家好,这里是承香墨影! Flutter 是 Google 发布的跨平台 UI 框架,而其中与 UI 相关的,最重要的就是 Widget & Element & Ren ...
- Flutter之基础Widget
原文博客地址: Flutter之基础Widget Flutter和Dart系列文章 项目GitHub地址 Flutter作为一种全新的响应式,跨平台,高性能, 完全免费.开源的移动开发框架 Widge ...
- Flutter学习-基础Widget
Flutter学习-基础Widget 1. Flutter编程范式 1.1 编程范式的理解 1.2 flutter的编程范式 2. Text Widget 2.1 普通文本展示 2.2 富文本 2.3 ...
- Flutter快速上车之Widget
Flutter作为一种全新的响应式,跨平台,高性能的移动开发框架.从开源以来,已经得到越来越多开发者的喜爱.闲鱼是最早一批与谷歌展开合作,并在重要的商品详情页中使用上线的公司.一路走来,积累了大量的开 ...
- Flutter快速上车之Widget 1
Flutter作为一种全新的响应式,跨平台,高性能的移动开发框架.从开源以来,已经得到越来越多开发者的喜爱.闲鱼是最早一批与谷歌展开合作,并在重要的商品详情页中使用上线的公司.一路走来,积累了大量的开 ...
- 跟我学flutter:细细品Widget(一)WidgetElement初识
前言 Everything's a widget! Widget Flutter 中 Widget是一个"描述一个UI元素的配置信息",Widget就是接受元素,而不是真是绘制的显 ...
- 重磅! flutter视图局部更新
新建一个flutter工程, 以flutter框架给我们自动生成的代码为例, 当我们点击按钮更新记数_counter时,最终是通过调用State<T>.setState来更新视图的: se ...
- Flutter学习-单子布局Widget
Flutter学习-单子布局Widget 1. 概述 2. Align 2.1 Align的对齐方式 2.2 Align的区域大小控制 2. Center 3. Padding 4. Containe ...
- Flutter学习-多子布局Widget
Flutter学习-多子布局Widget 1. Flex 2. Row组件 2.1 Row组件介绍 2.2 属性解析 2.2.1 mainAxisSize 2.2.2 mainAxisAlignmen ...
最新文章
- 皮一皮:像不像投产不顺利的你...
- Linux 内核 cgroups 新漏洞可导致攻击者逃逸容器
- Golang 任意类型切片的增删改查
- 深入.NET编程 第十一章 影院售票系统
- matlab 向量转置,matlab中向量和矩阵怎么转置 值得收藏
- HealthKit开发教程之HealthKit的主要类型数据
- 邓仰东专栏|机器学习的那些事儿(四):基于GPU的机器学习实例之AlphaGO
- VisionMobile:移动平台生态系统冲突报告(十二)Chapter C:iOS
- 重磅成果丨ASAM SOVD 1.0.0正式发布
- BGP边界网关路由协议
- 我会java什么梗_抖音不会真的有人什么梗 不会真的有人不会吧不会吧别恶心我梗意思及出处...
- 流量统计html代码,CNZZ数据专家
- 康奈尔大学计算机硕士要求,申请康奈尔大学计算机硕士需要什么条件呢
- 计算机与打印机未连接,win7系统无法打印提示似乎未连接打印机的恢复步骤
- Photoshop制作水晶立体字
- Thread.setDaemon设置说明
- Probability Through Experiments
- 想入行C++游戏脚本制作?首先听听7年经验大佬怎么说?
- 我终于读懂了原型模式。。。
- HugeGraph图数据库概念详解