"
我们知道 StatelessWidget 和 StatefulWidget 两种直接继承自 Widget 的类,在 Flutter 中,还有另一个类 RenderObjectWidget 也同样直接继承自 Widget,它没有 build 方法,可通过 createRenderObject 直接创建 RenderObject 对象放入渲染树中。Column 和 Row 等控件都间接继承自 RenderObjectWidget
"
主要属性和方法如下:
-
constraints 对象,从其父级传递给它的约束
-
parentData 对象,其父对象附加有用的信息。
-
performLayout 方法,计算此渲染对象的布局。
-
paint 方法,绘制该组件及其子组件。
RenderObject 作为一个抽象类。每个节点需要实现它才能进行实际渲染。扩展 RenderOject 的两个最重要的类是RenderBox 和 RenderSliver。这两个类分别是应用了 Box 协议和 Sliver 协议这两种布局协议的所有渲染对象的父类,其还扩展了数十个和其他几个处理特定场景的类,并实现了渲染过程的细节,如 RenderShiftedBox 和 RenderStack 等等。
布局约束
在上面,我们介绍组件渲染流程时,我们了解到了 Flutter 中的控件在屏幕上绘制渲染之前需要先进行布局(Layout)操作。其具体可分为两个线性过程:从顶部向下传递约束,从底部向上传递布局信息,其过程可用下图表示。

第一个线性过程用于传递布局约束。父节点给每个子节点传递约束,这些约束是每个子节点在布局阶段必须要遵守的规则。就好像父母告诉自己的孩子 :“你必须遵守学校的规定,才可以做其他的事”。常见的约束包括规定子节点最大最小宽度或者子节点最大最小的高度。这种约束会向下延伸,子组件也会产生约束传递给自己的孩子,一直到叶子结点。
第二的线性过程用来传递具体的布局信息。子节点接受到来自父节点的约束后,会依据它产生自己具体的布局信息,如父节点规定我的最小宽度是 500 的单位像素,子节点按照这个规则可能定义自己的宽度为 500 个像素,或者大于 500 像素的任何一个值。这样,确定好自己的布局信息之后,将这些信息告诉父节点。父节点也会继续此操作向上传递一直到最顶部。
下面我们具体介绍有哪些具体的布局约束可在树中传递。Flutter 中有两种主要的布局协议:Box 盒子协议和 Sliver 滑动协议。这里我们以盒子协议为例展开具体的介绍。
在盒子协议中,父节点传递给其子节点的约束为 BoxConstraints。该约束规定了允许每个子节点的最大和最小宽度和高度。如下图,父节点传入 Min Width 为 150,Max Width 为 300 的 BoxConstraints:

当子节点接受到该约束,便可以取得上图中绿色范围内的值,即宽度在 150 到 300 之间,高度大于 100,当取得具体的值之后再将取得具体的大小的值上传给父节点,从而达到父子的布局通信。
6 自定义一个 Center 控件
现在,我们可以应用前文中提到的布局约束与渲染树相关的概念自己定义一个类似居中布局的组件 RenderObject 对象渲染在屏幕上。
所以我们称自己自定义组件为 CustomCenter
void main() {
现在我们来实现我们的 CustomCenter:
class CustomCenter extends SingleChildRenderObjectWidget {
CustomCenter 继承了
SingleChildRenderObjectWidget,表明这个 Widget 只能有一个子控件,其中,createRenderObject(…) 方法用于真正创建并返回我们的 RenderObject 对象实例, 我们的 RenderObject 为 RenderCustomCenter,代码如下:
class RenderCustomCenter extends RenderShiftedBox {
RenderCustomCenter 继承自
RenderShiftedBox,该类是继承自 RenderBox。RenderShiftedBox 满足盒子协议,并且提供了 performLayout() 方法的实现。我们需要在 performLayout() 方法中布局我们的子元素。
我们在使用 child.layout(…) 方法布局 child 的时候传递了两个参数,第一个为 child 的布局约束,而另外一个参数是 parentUserSize, 该参数如果设置为 false,则意味着 parent 不关心 child 选择的大小,这对布局优化比较有用;因为如果 child 改变了自己的大小,parent 就不必重新 layout 了。但是在我们的例子中,我们的需要把 child 放置在 parent 的中心,就是 child 的大小(Size)一旦改变,则其对应的偏移量(Offset) 也会改变,于是 parent 需要重新布局,所以我们这里传递了一个 true。
当 child.layout(…) 完成了以后,child 就确定了自己的 Layout Details。然后我们就还可以为其设置偏移量来将它放置到我们想放的位置。在我们的例子中为 居中。
最后,和 child 根据 parent 传递过来的约束选择了一个尺寸一样,我们也需要为 CustomCenter 选择一个尺寸。
运行效果如下:

7 应用视图的构建
Flutter App 入口的部分发生于如下代码:
import ‘package:flutter/material.dart’;
runApp函数接受一个 Widget类型的对象作为参数,也就是说在 Flutter的概念中,只存在 View,而其他的任何逻辑都只为 View的数据、状态改变服务,不存在 ViewController(或者叫 Activity)。接下来看 runApp做了什么:
void runApp(Widget app) {
在runApp中,传入的 widget 被挂载到根 widget 上。这个 WidgetsFlutterBinding 其实是一个单例,通过 mixin 来使用框架中实现的其他 binding 的 Service,比如手势、基础服务、队列、绘图等等。然后会调用 scheduleWarmUpFrame 这个方法,从这个方法注释可知,调用这个方法会主动构建视图数据。这样做的好处是因为 Flutter 依赖 Dart 的 MicroTask 来进行帧数据构建任务的 schedule,这里通过主动调用进行整个周期的 “热身”,这样最近的下次 VSync 信号同步时就有视图数据可提供,而不用等到 MicroTask 的 next Tick。
然后我们再来看 attachRootWidget 这个函数干了什么:
void attachRootWidget(Widget rootWidget) {
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。




由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)

经、学习笔记、源码讲义、实战项目、讲解视频**
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
[外链图片转存中…(img-NRTpOyGj-1710924751629)]
文章介绍了Flutter中的RenderObjectWidget类,它不包含build方法,通过createRenderObject创建渲染对象。着重讨论了布局约束、Box协议、Sliver协议以及如何自定义一个居中布局的CustomCenter组件。此外,还涉及了FlutterApp的构建过程和WidgetsFlutterBinding的作用。
1183

被折叠的 条评论
为什么被折叠?



