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

Flutter基础技术:什么是Widget、RenderObject和Element?

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

你可能已经知道如何使用StatelessWidget和StatefulWidget了。但这些小部件只是将其他小部件组合在一起。添加到屏幕的布局和绘图发生在其他地方。

**我强烈建议你打开你最喜欢的编辑工具,然后按照本文一步步看看实际代码是如何实现的,并一路“结果”。 ,

## 不透明度组件
最好从不透明度组件开始。这个小部件非常简单,也是一个很好的例子。

它只接受一个子组件。因此,您可以设置任何小部件的不透明度来更改其显示。还有一个值 Opacity,该值介于 0.0 和 1.0 之间。它用于控制透明度。

OpacitySingleChild RenderObject Widget的子类。传承路径是这样的:

Opacity -> SingleChildRenderObjectWidget -> RenderObjectWidget -> Widget。

StatelessWidgetStatefulWidget是这样的:StatelessWidgetStatefulWidget是这样的:d一起,d'组件不透明度控制组件的绘制方式。

但是如果你想找到一些从不透明度代码中绘制像素的提示,那几乎是徒劳的。这是因为小部件仅包含配置信息。例如,组件 opacity 仅包含不透明度值。

这就是为什么您可以在组件的 build 方法中创建新的小部件。它不包含任何构建组件的消耗资源的代码,而仅包含构建的一些信息。

绘画

绘画时会发生什么?

RenderObject

图纸都是在RenderObject完成的。 光看名字就知道了。 Opacity 组件像这样创建和更新 RenderObject:

@override
RenderOpacity createRenderObject(BuildContext context) => new RenderOpacity(opacity: opacity);

@override
void updateRenderObject(BuildContext context, RenderOpacity renderObject) {
  renderObject.opacity = opacity;
}

RenderOpacity

Opacity组件将其自身的大小和子组件的大小设置为相同的值。除了绘图之外,它与其子组件的所有其他方面基本上相同。在绘制子组件之前添加不透明度值。

在这种情况下,RenderOpacity必须实现所有方法(例如执行布局、碰撞检测和计算大小),然后交给子类来做具体的工作。

RenderOpacity继承RenderProxyBox(此类混合在其他一些类中)。这些类分别实现了上述方法。

double get opacity => _opacity;
double _opacity;
set opacity(double value) {
  _opacity = value;
  markNeedsPaint();
}

我(作者)删除了大部分代码。如果您想查看完整的代码,可以在这里查看。

getter 暴露了私有值。 setter 调用 markNeedsPaint()markNeedsLayout()。顾名思义,它会通知系统“这个组件发生了变化,需要重新绘制或者重新布局”

RenderOpacity:

@override
void paint(PaintingContext context, Offset offset) {
    context.pushOpacity(offset, _alpha, super.paint);
}

Context中也有这样的代码是一块画布。这个画布上有一个方法叫做 pushOpacity

这一行就是opacity的具体实现。 Review

  • opacity不是upStatelessWidgetStatefullwidget,但alechildRendeObjectWidgetWidget。
  • 组件仅包含绘制所需的信息。例如,组件 Opacity 包含值 Opacity
  • RenderOpacity,继承自RenderProxyBox,执行特定的布局和绘制动作
  • 由于其作为子组件的opacity方法与子组件相同,
  • 重写了color方法,它将特定的不透明度值分配给不透明度的子组件

就这些了吗?

记住,小部件只是一种配置,RenderObject是管理布局和绘图的。

在 Flutter 中,您基本上总是创建新的小部件。当调用方法 build() 时,您将创建许多组件。 build方法基本上是在发生各种变化时调用的。例如,在动画中经常调用构建方法。 最好不要每次都绘制整个子树,更新会更好。

您无法获取屏幕上组件的大小或位置,因为组件表现为蓝图,并且实际上并未绘制在界面上。它仅包含渲染对象所需的信息。

Element

Element 是组件树的实际组件。

发生了什么

第一次创建组件时,创建了一个元素,并将两者链接在一起。然后该元素被插入到树中。如果组件(小部件)发生变化,请将其与旧组件进行比较并相应地更新元素。最重要的是,此时的元素并没有再次创建,而只是更新。

Element 是 Fl​​utter 核心的一部分,但你现在不需要知道。这些就足够了。

不透明组件的元素在哪里创建的

请参阅如果你好奇的话。在 SingleChildRenderObectWidget 中,

@override
SingleChildRenderObjectElement createElement() => new SingleChildRenderObjectElement(this);

SingleChild RenderObject Element 也只是一个具有一个子元素的元素。

Element创造了RenderObject

如果Element创造了RenderObject,那么RenderObject自己是如何创造不透明组件的呢?

基本上是因为不透明度组件只需要RenderObject,但不需要自定义元素。

参见以下代码:

SingleChildRenderObjectElement(SingleChildRenderObjectWidget widget) : super(widget);

SingleChildRenderObject元素参考了RenderObjectWidget并且也包含在此处)。

RenderObjectElement#mount方法中,将元素插入到元素树中:

@override
void mount(Element parent, dynamic newSlot) {
  super.mount(parent, newSlot);
  _renderObject = widget.createRenderObject(this);
  attachRenderObject(newSlot);
  _dirty = false;
}

当元素被挂载时,组件只允许创建渲染对象。

最后

这就是不透明度组件的工作原理。

我的目标是通过这篇文章来介绍组件背后的原理。还有很多我没有涉及到,但我希望这篇文章至少能让您一睹其风采。

版权声明

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

发表评论:

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

热门