十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
对于初学flutter的朋友来说,要知道,flutter的UI万物皆Widget。
为善左等地区用户提供了全套网页设计制作服务,及善左网站建设行业解决方案。主营业务为网站建设、成都网站制作、善左网站设计,以传统方式定制建设网站,并提供域名空间备案等一条龙服务,秉承以专业、用心的态度为用户提供真诚的服务。我们深信只要达到每一位用户的要求,就会得到认可,从而选择与我们长期合作。这样,我们也可以走得更远!
flutter所写的页面的结构可以被看成套娃,一层套一层,一层套一层,一层套一层。。。。。。
Flutter Widget采用现代响应式框架构建,这是从 React 中获得的灵感,中心思想是用widget构建你的UI。 Widget描述了他们的视图在给定其当前配置和状态时应该看起来像什么。当widget的状态发生变化时,widget会重新构建UI,Flutter会对比前后变化的不同, 以确定底层渲染树从一个状态转换到下一个状态所需的最小更改。
Text : 该 widget 可让创建一个带格式的文本。
Row 、 Column : 这些具有弹性空间的布局类Widget可让您在水平( Row )和垂直( Column )方向上创建灵活的布局。
Stack :取代线性布局 (和Android中的LinearLayout相似),Stack允许子 widget 堆叠, 你可以使用 Positioned 来定位他们相对于 Stack 的上下左右四条边的位置。
Container : Container 可让您创建矩形视觉元素。 您可以为 Container 装饰一个 BoxDecoration , 如 background、一个边框、或者一个阴影。 Container 也可以具有边距(margins)、填充(padding)和应用于其大小的约束(constraints)。另外, Container 可以使用矩阵在三维空间中对其进行变换。
具体的演示见我另外的博客
有一部分Widget都有一个 child 属性,用于容纳唯一的子Widget。
例如:Container、Center、Padding、Align等Widget。
还有一部分Widget允许存在多个子Widget,用 children 作为属性。
例如:Row、Column、Stack等Widget。
在StatefulWidget调用createState之后,框架将新的状态插入树种,然后调用状态对象的initState。子类化State可以重写initState,以完成仅需要一次执行的工作。当然在initState的实现中需要调用super.initState
当一个状态对象不再需要时,框架调用状态对象的dispose。也可以通过覆盖dispose方法来执行清理工作。
OVER~
页面中的各界面元素(Widget)以树的形式组织,即控件树。Flutter通过控件树中的每个控件创建不同类型的渲染对象,组成渲染对象树。而渲染对象树在Flutter的展示过程分为三个阶段:布局、绘制、合成和渲染。
(一)布局
Flutter采用深度优先机制遍历渲染对象树,决定渲染对象树中各渲染对象在屏幕上的位置和尺寸。在布局过程中,渲染对象树中的每个渲染对象都会接收父对象的布局约束参数,决定自己的大小,然后父对象按照控件逻辑决定各个子对象的位置,完成布局过程。
为了防止因子节点发生变化而导致整个控件树重新布局,Flutter加入了一个机制——布局边界(Relayout Boundary),可以在某些节点自动或手动地设置布局边界,当边界内的任何对象发生重新布局时,不会影响边界外的对象,反之亦然。
二)绘制
布局完成后,渲染对象树中的每个节点都有了明确的尺寸和位置。Flutter会把所有的渲染对象绘制到不同的图层上。与布局过程一样,绘制过程也是深度优先遍历,而且总是先绘制自身,再绘制子节点。
以下图为例:节点1在绘制完自身后,会再绘制节点2,然后绘制它的子节点3、4和5,最后绘制节点6。
可以看到,由于一些其他原因(比如,视图手动合并)导致2的子节点5与它的兄弟节点6处于了同一层,这样会导致当节点2需要重绘的时候,与其无关的节点6也会被重绘,带来性能损耗。
为了解决这一问题,Flutter提出了与布局边界对应的机制——重绘边界(Repaint Boundary)。在重绘边界内,Flutter会强制切换新的图层,这样就可以避免边界内外的互相影响,避免无关内容置于同一图层引起不必要的重绘。
重绘边界的一个典型场景是Scrollview。ScrollView滚动的时候需要刷新视图内容,从而触发内容重绘。而当滚动内容重绘时,一般情况下其他内容是不需要重绘的,这时候重绘边界就派上用场了。
(三)合成和渲染
终端设备的页面越来越复杂,因此Flutter的渲染树层级通常很多,直接交付给渲染引擎进行多图层渲染,可能会出现大量渲染内容的重复绘制,所以还需要先进行一次图层合成,即将所有的图层根据大小、层级、透明度等规则计算出最终的显示效果,将相同的图层归类合并,简化渲染树,提高渲染效率。
合并完成后,Flutter会将几何图层数据交由Skia引擎加工成二维图像数据,最终交由GPU进行渲染,完成界面的展示。
四、总结
咱们从各种业界主流跨端方案与Flutter的对比开始,到Flutter的简要介绍以及Flutter的运行机制,并以界面渲染过程为例,从布局、绘制、合成和渲染三个阶段讲述了Flutter的实现原理。相信大家对Flutter已经有一个整体认知,赶快一起上手操作起来吧!
抽象类Element 有mount方法
抽象类Widget 有createElement方法
RenderObjectWidget有createElement方法 和 createRenderObject方法
每一个Widget, 都有createElement方法,通过createElement方法 创建一个Element对象,
Element加入Element树中,它会创建三种Element ,每个Element 有个mount方法
第一种:RenderObjectElement(RenderObjectWidget的createElement方法)
mount方法中 调用
widget.createRenderObject(this) ,创建RenderObject对象,RenderObject对象加入Render树中
第二种:StatefulElement继承ComponentElement
第三种:StatelessElement继承ComponentElement
并不是所有的Widget都会被独立渲染!只有继承RenderObjectWidget的才会创建RenderObject对象!
RenderObjectWidget 是 Widget 例如 SizeBox , Column 等
RenderObjectElement 是这类 Widget 生成的 Element 类型,
例如 SizeBox 对应 SingleChildRenderObjectElement (单子节点的 Element )
RenderObject 才是真正负责绘制的对象,其中包含了 paint , layout 等方法~
Text 组件为例:
class Text extends StatelessWidget
Text build返回的是
class RichText extends MultiChildRenderObjectWidget
MultiChildRenderObjectWidget - MultiChildRenderObjectElement
RenderObjectElement 会重写 mount
遍历 _parent (就是上个节点的 element ,这个 _parent 在每次的 mount 方法设置),一直遍历知道找到最近的一个 RenderObjectElement
在回顾下 inflateWidget
SingleChildRenderObjectElement
MultiChildRenderObjectElement
inflateWidget 会触发 RenderObjectWidget 的 createElement 创建 RenderObjectElement ,
再调用 RenderObjectElement 的 mount 方法
mount 方法调用 RenderObjectWidget 的 createRenderObject 方法创建 RenderObject
然后找到最近的一个父 RenderObjectElement 调用 insertRenderObjectChild 插入 RenderObject
(注意:这里不是 RenderObjectElement 的 child ,而是 RenderObjectElement 关联的 RenderObject 的 child , element 树里面都是 element , RenderObject 树里面都是 RenderObject )
MultiChildRenderObjectElement 多子节点挂载逻辑
多节点添加子节点逻辑
每个子节点的 parentData 的 after 用来指向前一个子节点 previous 指向下一个子节点