学习flutter必备之原理理解

简介: 这是我参与8月更文挑战的第 12 天,活动详情查看:8月更文挑战。为应掘金的八月更文挑战,Flutter,什么是 Widgets、RenderObjects 和 Elements?有没有想过 Flutter 如何获取这些小部件并将它们实际转换为屏幕上的像素?不?你应该!

这是我参与8月更文挑战的第 12 天,活动详情查看:8月更文挑战。为应掘金的八月更文挑战

Flutter,什么是 Widgets、RenderObjects 和 Elements?

有没有想过 Flutter 如何获取这些小部件并将它们实际转换为屏幕上的像素?不?

你应该!

了解底层技术的工作原理是优秀开发人员和优秀开发人员之间的区别。

当您知道哪些有效,哪些无效时,您可以更轻松地创建自定义布局和特殊效果;知道这一点可以让您在键盘上度过几个漫长的夜晚。

这篇文章的目的是向您介绍 flutter 表面之外的世界。我们将看看 Flutter 的不同方面,并了解它的实际工作原理。

让我们开始吧

您可能已经知道如何使用 StatelessWidget 和 StatefulWidget。但是这些小部件只组成其他小部件。布置小部件并渲染它们发生在其他地方。

我强烈建议打开你最喜欢的 IDE 并跟随,查看实际代码中的结构通常会产生那些“啊哈”时刻。在 Intellij 中,您可以双击 shift 并输入类名来查找它。

不透明度

为了熟悉 flutter 工作原理的基本概念,我们将查看Opacity小部件并检查它。因为它是一个非常基本的小部件,所以它是一个很好的例子。

它只接受一个child。因此,您可以将任何小部件包装在 中Opacity并更改其显示方式。除了孩子之外,只有一个参数被调用opacity,它是一个介于 0.0 和 1.0 之间的值。它控制不透明度(废话)。

The Widget

Opacity是一个SingleChildRenderObjectWidget.

扩展类扩展的层次结构是这样的:

Opacity → SingleChildRenderObjectWidget → RenderObjectWidget → Widget

相比之下,StatelessWidget 和 StatefulWidget 如下所示:

StatelessWidget/StatefulWidget → Widget

不同之处在于 Stateless/StatefulWidget 只组成小部件,而 Opacity 小部件实际上改变了小部件的绘制方式。

但是,如果您查看这些类中的任何一个,您将找不到与实际绘制不透明度相关的任何代码。

那是因为小部件只保存配置信息。 在这种情况下,不透明度小部件仅保存不透明度值。

这就是每次调用构建函数时都可以创建新小部件的原因。因为小部件的构建成本并不高。它们只是信息的容器。

渲染

但是,在没有渲染发生的呢?

它在 RenderObjects 中

从名称中您可能已经猜到,RenderObject 负责一些事情,包括渲染。

Opacity 小部件使用这些方法创建和更新 RenderObject。

@override
RenderOpacity createRenderObject(BuildContext context) => new RenderOpacity(opacity: opacity);
@override
void updateRenderObject(BuildContext context, RenderOpacity renderObject) {
  renderObject.opacity = opacity;
}
复制代码

source

渲染不透明度

Opacity部件尺寸本身是完全相同的大小作为其子一样。It basically mimics every aspect of the child but the painting. 在绘制它的孩子之前,它会为其添加不透明度。

在这种情况下,RenderOpacity 需要实现所有方法 (例如执行布局/ hit testing/ 计算大小) 并要求其子项执行实际工作.

The RenderOpacity extends the RenderProxyBox (which mixes in a few other classes). Those are exactly implementing those methods and deferring the actual calculation to the only child.

它基本上模仿了孩子的每一个方面 ,但画。

(例如执行布局/命中测试/计算大小)。

RenderOpacity扩展了RenderProxyBox(在几个其他类融合)。那些正是实施这些方法并将实际计算推迟到唯一的孩子。

double get opacity => _opacity;
double _opacity;
set opacity(double value) {
  _opacity = value;
  markNeedsPaint();
}
复制代码

我在这段代码中删除了很多断言/优化。查看完整方法的原文source

字段通常向私有变量公开一个 getter。还有一个 setter,它除了设置字段外,还调用markNeedsPaint()or markNeedsLayout() 顾名思义,它告诉系统“嘿我已经改变了,请重新绘制/重新布局我”。

在里面RenderOpacity我们找到了这个方法:

Inside the RenderOpacity we find this method:

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

同样,删除了优化和断言.source

PaintingContext基本上是一个奇特的画布。在这个漂亮的画布上有一个叫做 pushOpacity 的方法

The PaintingContext is basically a fancy canvas. And on this fancy canvas there is a method called pushOpacity. BINGO.

这一行是实际的不透明度实现。

回顾一下

  • Opacity不是StatelessWidgetStatefulWidget而是一个SingleChildRenderObjectWidget
  • Widget仅持有该渲染器可以使用的信息。
  • 在这种情况下,Opacity持有一个代表不透明度的双精度值。
  • RenderOpacity,它扩展了RenderProxyBox执行实际布点/渲染等。
  • 因为 opacity 的行为与其子级几乎完全一样,所以它将每个方法调用委托给子级。
  • 它覆盖了paint 方法并调用pushOpacity,这将向小部件添加所需的不透明度。

请记住,小部件只是一个配置,RenderObject唯一管理布局/渲染等。

在 Flutter 中,您基本上一直在重新创建小部件。当您的build()方法被调用时,您将创建一堆小部件。每次发生变化时都会调用此构建方法。例如,当一个动画发生时,build 方法会经常被调用。这意味着您不能每次都重建整个子树。相反,您想要更新它。

您无法获得小部件在屏幕上的大小或位置,因为小部件就像蓝图,实际上并不在屏幕上。它只是对底层渲染对象应该使用哪些变量的描述。

元素介绍

元素是大树中的具体小部件。

基本上发生的事情是:

第一次创建小部件时,它会膨胀为Element. 然后元素被插入到树中。如果小部件稍后发生更改,则会将其与旧小部件进行比较,并且元素会相应地更新。重要的是,元素不会被重建,它只会被更新。

元素是核心框架的核心部分,显然它们还有更多内容,但现在这些信息已经足够了。

不透明度示例中创建的元素在哪里?

对于那些好奇的人来说,只是一小段。

SingleChildRenderObjectWidget创建它。

@override
SingleChildRenderObjectElement createElement() => new SingleChildRenderObjectElement(this);
复制代码

source

而这SingleChildRenderObjectElement只是一个只有一个孩子的元素。

该元素创建了 RenderObject,但在我们的例子中,Opacity 小部件创建了它自己的 RenderObject?

这只是为了流畅的 API。因为更多时候不是,小部件需要一个RenderObject但没有自定义Element. 该RenderObject实际上是由创造Element,让我们一起来看看:

SingleChildRenderObjectElement(SingleChildRenderObjectWidget widget) : super(widget);
复制代码

SingleChildRenderObjectElement获取到reference to RenderObjectWidget(其中有创建的方法RenderObject)。

mount 方法是将元素插入元素树的地方,这里发生了神奇的事情(RenderObjectElement 类):

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

(Right after super.mount(parent,newSlot);source

只有一次(当它被安装时)它会询问小部件“请给我你想要使用的渲染对象,以便我可以保存它”。

结束

就是这样。这就是不透明度小部件在内部的工作方式。

我这篇文章的目标是向您介绍小部件之外的世界。还有很多话题要讨论,但我希望我能给你一个很好的内部工作介绍。


相关文章
|
12天前
|
设计模式 移动开发 开发框架
如何学习 Flutter 框架?
学习 Flutter 需要耐心和持续的努力,通过系统的学习、实践、交流和不断跟进最新技术,你将逐渐掌握 Flutter 框架,并能够开发出高质量的移动应用。
|
23天前
|
开发者 容器
Flutter&鸿蒙next 布局架构原理详解
本文详细介绍了 Flutter 中的主要布局方式,包括 Row、Column、Stack、Container、ListView 和 GridView 等布局组件的架构原理及使用场景。通过了解这些布局 Widget 的基本概念、关键属性和布局原理,开发者可以更高效地构建复杂的用户界面。此外,文章还提供了布局优化技巧,帮助提升应用性能。
82 4
|
23天前
|
存储 Dart 前端开发
flutter鸿蒙版本mvvm架构思想原理
在Flutter中实现MVVM架构,旨在将UI与业务逻辑分离,提升代码可维护性和可读性。本文介绍了MVVM的整体架构,包括Model、View和ViewModel的职责,以及各文件的详细实现。通过`main.dart`、`CounterViewModel.dart`、`MyHomePage.dart`和`Model.dart`的具体代码,展示了如何使用Provider进行状态管理,实现数据绑定和响应式设计。MVVM架构的分离关注点、数据绑定和可维护性特点,使得开发更加高效和整洁。
149 3
|
24天前
|
存储 缓存 JavaScript
Flutter 学习之封装 WebView
【10月更文挑战第24天】通过以上的探讨,我们可以看出,在 Flutter 中封装 WebView 是非常有必要的,它可以提高代码的复用性、增强可维护性、提供统一接口。在实际应用中,我们需要根据具体的需求和场景,选择合适的封装方法和技术,以实现更好的效果。
|
29天前
动画控制器在 Flutter 中的工作原理
【10月更文挑战第18天】总的来说,动画控制器 `AnimationController` 在 Flutter 中起着关键的作用,它通过控制动画的数值、速度、节奏和状态,实现了丰富多彩的动画效果。理解它的工作原理对于我们在 Flutter 中创建各种精彩的动画是非常重要的。
|
1月前
|
Dart 开发者 Windows
flutter:dart的学习
本文介绍了Dart语言的下载方法及基本使用,包括在Windows系统上和VSCode中的安装步骤,并展示了如何运行Dart代码。此外,还详细说明了Dart的基础语法、构造函数、泛型以及库的使用方法。文中通过示例代码解释了闭包、运算符等概念,并介绍了Dart的新特性如非空断言操作符和延迟初始化变量。最后,提供了添加第三方库依赖的方法。
30 12
|
1月前
|
容器
Flutter&鸿蒙next 布局架构原理详解
Flutter&鸿蒙next 布局架构原理详解
|
4月前
|
Dart JavaScript Java
flutter 架构、渲染原理、家族
flutter 架构、渲染原理、家族
90 3
|
3月前
|
Dart 开发工具 Android开发
Flutter学习:从搭建环境到运行
Flutter学习:从搭建环境到运行
45 0
|
4月前
|
索引
flutter-其他学习
flutter-其他学习
下一篇
无影云桌面