Code前端首页关于Code前端联系我们

Flutter 入门 - Widget、Element和 RenderObject 的起源

terry 2年前 (2023-09-22) 阅读数 74 #移动小程序

Flutter入门——Widget、Element和RenderObject的由来

可能是因为这些文章的切入点不同(或者是我的愚蠢),当我第一次学习 Flutter 时(甚至在我开始使用它一段时间后) ),无法完全理解这三棵树。他的角色是什么?大概最大的好处就是和面试官打交道……

经过一段时间的学习,我将自己对这三类(最基本的职责)的理解总结如下。希望对您深入了解Widget、Element、RenderObject有所帮助。

Widget、Element和RenderObject

纯属个人愚见,如有错误还请指出,谢谢。
复制代码

Widget

在古代,如果古人想要通过 Flutter 创建一个(100*100)的蓝色正方形,必须执行以下操作:

来自 :https://juejin.cn/post/6844904104452440072  
		作者:恋猫de小郭

import 'dart:ui' as ui;

void main() {
  ui.window.onBeginFrame = beginFrame;

  ui.window.scheduleFrame();
}

void beginFrame(Duration timeStamp) {
  final double devicePixelRatio = ui.window.devicePixelRatio;

  ///创建一个画板、录制绘制指令
  final ui.PictureRecorder recorder = ui.PictureRecorder();

  ///基于画板创建一个 Canvas
  final ui.Canvas canvas = ui.Canvas(recorder);
  canvas.scale(devicePixelRatio, devicePixelRatio);
  
  //布局
  var centerX = ui.window.physicalSize.width / 2.0;
  var centerY = ui.window.physicalSize.height / 2.0;
  
  ///画一个 100 的剧中蓝色
  Paint blueP = new Paint()..color = Colors.blue;
  
  canvas.drawLine(Offset.zero,Offset(100,0),blueP);
  canvas.drawLine(Offset(100,0),Offset(100,100),blueP);
  canvas.drawLine(Offset(100,100),Offset(0,100),blueP);
  

  ///停止录制绘制指令
  final ui.Picture picture = recorder.endRecording();
  
  //布局
  final ui.SceneBuilder sceneBuilder = ui.SceneBuilder()
    ..pushOffset(centerX, centerY)
    ..addPicture(ui.Offset.zero, picture)
    ..pop();

  ui.window.render(sceneBuilder.build());
}

复制代码

之后经过以上的操作序列,‘蓝色方块’诞生了:

Flutter入门——Widget、Element和RenderObject的由来

经过长时间的使用,绘制方块的四行代码被优化为:

 //很明显这个要比上面那4行更易读、且简便。
 //也算是初代之一的‘轮子’了。
  canvas.drawRect(
      Rect.fromCenter(
          center: Offset.zero,
          width: 100,
          height: 100),
          blueP);
复制代码

经过很长一段时间,随着轮子的不断迭代,终于演变为以下内容:

	Container(
    color:Colors.blue
    width:100,height:100)
复制代码

这就是我们Widget的起源。

Element

借助小部件(滚轮)的便利,我只用了一天时间就创建了一个漂亮的页面:

Flutter入门——Widget、Element和RenderObject的由来

还可以交互:

点击 圆的时候,两个圆颜色互换
点击 方块时,黄色变成了白色
点击 三角时,三角就消失了,再点击空白位置会复现。
复制代码

为了实现这个功能,我创建了一个漂亮的页面在 widget 中添加了很多标志(flags)来表示哪些需要更新、删除、插入等,并且添加了函数来实现相应的功能。

一切都完成后,我的代码一团糟,难以阅读——我花了10分钟写代码,又花了5分钟滚动页面……

因此element诞生了——它是主要负责增删改查widget,哪些不需要更新,哪些需要重建等等,我们看它的方法就一目了然了。

....省略代码

void update(covariant Widget newWidget)

Element inflateWidget(Widget newWidget, dynamic newSlot)

void markNeedsBuild()

void performRebuild();

Element updateChild(Element child, Widget newWidget, dynamic newSlot)

....省略代码


复制代码

RenderObject

元素的添加使我的页面代码更加简洁。同时,我的页面还添加了新的炫酷功能:

双击页面后,会出现一个灰色矩形,盖住原来的图形,并且左右晃动。
复制代码

Flutter入门——Widget、Element和RenderObject的由来

功能写完后,测试机运行起来,我的主机直接蓝屏。

这是不可能的。向老板要钱是没有希望的。为了省钱,他还是用算盘算账……只能优化代码。

经过观察,发现几个可以优化的地方:

1, 之前的‘方块’和‘三角’被遮挡了,那么再画它们也没啥意义,布局也可以省了

2, 上面两个圆,就没动过,所以布局啊、绘制啥的都没必要再跑一遍

3, 灰色方块,大小没变,颜色也没变,我觉得只要调整它的位置就行
复制代码

先添加7、8勺Flag,再添加10勺左右的功能...

...忙了一段时间工作后,在旧机器上。功能完美。

但是我的代码又臃肿了,所以我只是提取了另一个类,就像之前的元素一样,来帮助我管理绘图、布局、命令捕获(实际上封装在PaintContext中)等等:

‘于是,便有了RenderObject。’
复制代码

我们可以看到。我们来看看方法:

...省略代码

markNeedsLayout();
markNeedsPaint();
void performLayout();
void performResize();
void paint(PaintingContext context, Offset offset)

...省略代码

复制代码

重构

我添加了三个类之后,评估了他们的职责:

widget  方便我构建图像
element 帮我增删改查
renderObject 帮我负责布局、绘制等

同时,由于element的职能,他应该持有Widget和Renderobject
复制代码

经过一系列的设计和重构,我的页面架构最终变成了这样:

Flutter入门——Widget、Element和RenderObject的由来

这个完成widget、element、renderObject的基本职责。希望通过上面的文字大家能够对这三者有一个初步的了解。

作者:Jihada

来源:掘金

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

热门