Flutter 核心原理 - UI 框架(UI Framework)

news2024/10/7 18:28:02

Flutter 既能保证很高的开发效率,又能获得很好的性能。 

这两年 Flutter 技术热度持续提高,整个 Flutter 生态和社区也发生了翻天覆地的变化。目前Flutter 稳定版发布到了3.0,现在已经支持移动端、Web端和PC端,通过Flutter 开发的应用程序能够轻松的在各个平台迁移并获得很好的性能。另外,Flutter 在 Github Star 数上排名已经进入了前20,在跨端框架中已经成为稳稳的第一。

根据近几年实践统计,Flutter 相比原生开发,人效能提高近一倍,且性能可以接近原生。

Flutter 源起 


Flutter 属于在实现三个跨端框架方向之一的“自绘UI + 原生”的范畴。在上一篇中也介绍过。

Flutter 实现一套自绘UI引擎,并拥有一套自己的 UI 布局框架。

得益于但Dart开发语言的JIT 运行方式支持动态化的。因此,在开发过程中 Flutter 的热重载可帮助开发者快速地进行测试、构建UI、添加功能并更快地修复错误。在 iOS 和 Android 模拟器或真机上可以实现毫秒级热重载,并且不会丢失状态。

Flutter 从上到下分为UI框架层、引擎层和嵌入层。开发者基本上都是与UI框架层打交道。 


UI 框架

UI 框架(UI Framework)指基于一个操作系统和浏览器之上快速开发GUI(图形用户接口)的框架。通常来讲平台只提供非常基础的图形 API(Canvas),如画线、画几何图形等。

可以想象一下,如果没有UI 框架的封装而直接用 Canvas 来构建用户界面将会是怎样的一个体验和效率!

简单来讲, UI 框架解决的主要问题就是:如何基于基础的图形API(Canvas)来封装一套可以高效创建UI的框架

各个平台 UI 框架的实现原理基本是相通的,在介绍Flutter UI框架之前,可以先了解平台图形处理的基本原理。操作系统(Android&IOS)图像绘图的基本原理-CSDN博客


Flutter UI框架

Android SDK封装了Android操作系统API,提供了一个“UI描述文件 XML+Java/Kotlin 操作 DOM”的UI 框架。iOS的 UIKit 对 View 的抽象也是一样的。他们都将操作系统API抽象成一个基础对象,然后再定义一套规则来描述UI,如UI树结构,UI 操作的单线程原则等。

如果可以使用同一种编程语言开发,在不同操作系统API上封装一个对上接口一致,对下适配不同操作系统的中间层。那么我们就可以使用同一套代码编写跨平台的应用了。

而Flutter的原理正是如此:它提供了一套Dart API,然后在底层通过OpenGL这种跨平台的绘制库(内部会调用操作系统API)实现了一套代码跨多端。

由于Dart API也是调用操作系统API,所以它的性能接近原生。

*注解:

  1. 虽然Dart是先调用了OpenGL,OpenGL才会调用操作系统API,但是这仍然是原生渲染,因为OpenGL只是操作系统API的一个封装库,它并不像WebView渲染那样需要 JavaScript 运行环境和CSS渲染器,所以不会有性能损失。
  2. Flutter 早期版本底层会调用 OpenGL 这样的跨平台库,但在 iOS 设备上苹果提供了专门的图形库Metal,使用 Metal可以在iOS上获得比OpenGL更好的绘图性能,因此Flutter后来在 iOS 上会优先调用 Metal ,只有当 Metal 不可用时才会降级到OpenGL。不过 Flutter 底层到底是调用的哪个库,作为应用开发者是不需要关注的,我们只需要知道调用的是原生的绘图接口,可以保证高性能即可。

FlutterUI框架

简单概括:组合+响应式

在Flutter开发UI中,一切皆是Widget。我们要开发一个UI界面,需要组合不同Widget来实现。而当UI要发生变化时,我们不去直接修改DOM,而是通过更新状态State,让Flutter UI 框架来根据新的状态来重新构建UI。

先介绍一下BuildContext、RenderObject、Element,它们是组成Flutter UI 框架的基石。


​BuildContext

StatelessWidgetStatefulWidgetbuild方法都会传一个BuildContext对象。

Widget build(BuildContext context) {}

我们也知道,在很多时候我们都需要使用这个context 做一些事,比如:

Theme.of(context) //获取主题
Navigator.push(context, route) //入栈新路由
context.findRenderObject() //查找当前或最近的一个祖先RenderObject

那么BuildContext到底是什么呢,查看其定义,发现其是一个抽象接口类:

abstract class BuildContext {
    ...
}

那这个context对象对应的实现类到底是谁呢?以StatelessElement为例:

class StatelessElement extends ComponentElement {
  ...
  @override
  Widget build() => widget.build(this);
  ...
}

发现build传递的参数是this。这个BuildContext的实现类就是StatelessElement

虽然StatelessElementStatefulElement并没有实现BuildContext接口,但它们继承自Element类,而Element类实现了BuildContext接口:

class Element extends DiagnosticableTree implements BuildContext {
    ...
}

结论:BuildContext就是widget对应的Element。所以,我们可以通过contextStatelessWidgetStatefulWidgetbuild方法中访问到Element对象。


RenderObject 

RenderObject的主要职责是Layout布局和绘制。

所有的RenderObject会组成一棵渲染树“Render Tree”。

RenderObject就是渲染树中的一个对象,它可以实现事件响应以及布局、绘制、显示。

RenderObject类本身实现了一套基础的布局和绘制协议。 它本身没有定义坐标系统和具体的布局协议。为此,Flutter框架提供了一个RenderBox 的盒模型布局和基于 Sliver 的按需加载模型。布局坐标系统采用笛卡尔坐标系,屏幕的(top, left)是原点。

一个Element都对应一个RenderObject,我们可以通过Element.renderObject 来获取。


Element

我们知道UI树其实是由一个个独立的Element节点构成。Element就是Widget在UI树具体位置的一个实例化对象。

所有Element的RenderObject构成一棵树,我们称之为”Render Tree“即”渲染树“。

UI框架的三棵树:Widget树、Element树、渲染树。

Element树根据Widget树生成,而渲染树又依赖于Element树。

从创建到渲染的流程是:根据Widget生成Element,然后创建相应的RenderObject并关联到Element.renderObject属性上,最后再通过RenderObject来完成布局排列和绘制。

其实对于开发者来说只需要关注Widget树就行,Flutter框架已经将对Widget树的操作映射到了Element树上,这可以极大的降低复杂度,提高开发效率。

但是了解Element对理解整个Flutter UI框架是至关重要的,Flutter正是通过Element这个纽带将Widget和RenderObject关联起来。

了解Element层不仅会帮助读者对Flutter UI框架有个清晰的认识,而且也会提高自己的抽象能力和设计能力。

Element的生命周期
  1. Framework 调用Widget.createElement 创建一个Element实例,记为element
  2. element调用所对应Widget的createRenderObject方法创建与element相关联的RenderObject对象。然后element.attachRenderObjectrenderObject添加到渲染树。此时element就处于“active”状态,就可以显示在屏幕上了
  3. 当有父Widget的配置数据改变时,同时其State.build返回的Widget结构与之前不同,就需要重新构建对应的Element树。此时Element会先尝试复用旧树上相同位置的element。通过调用Widget.canUpdate方法判断newWidgetoldWidgetruntimeTypekey是否同时相等,如果同时相等就返回true复用旧Element。否则就创建新的Element。
  4. 当Widget树结构发生了变化,导致element对应的Widget被移除时,该祖先Element就会调用deactivateChild 方法来移除element。Framework会调用element.deactivate 方法,这时element状态变为“inactive”状态。“inactive”态的element将不会再显示到屏幕。
  5. 如果element要重新插入到Element树其他的位置,Framework会先将element从现有位置移除,然后再调用其activate(激活方法,将其renderObject重新attach到渲染树。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1524657.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【计算机视觉】二、图像形成——实验:2D变换编辑器2.0(Pygame)

文章目录 一、向量和矩阵的基本运算二、几何基元和变换1、几何基元(Geometric Primitives)2、几何变换(Geometric Transformations)2D变换编辑器0. 项目结构1. Package: guibutton.pywindow.py1. __init__(self, width, height, title)2. add_buttons(self)3. clear(self)4. dr…

WEB前端 HTML 列表表格

列表 有序列表 使用“ol”创建“有序列表”&#xff0c;使用“li”表示“列表项” <body><ol type"1"><li>列表1</li><li>列表2</li><li>列表3</li></ol><ol type"A"><li>列表A<…

Redis进阶——redis消息队列

目录 redis消息队列认识消息队列基于List实现消息队列如何基于List结构模拟消息队列基于List的消息队列有哪些优缺点&#xff1f; 基于PubSub的消息队列基于Stream的消息队列读取消息的方式之一&#xff1a;XREAD基于Stream的消息队列–消费者组redis三种消息队列的对比 Stream…

Spring炼气之路(炼气二层)

一、bean的配置 1.1 bean的基础配置 id&#xff1a; bean的id&#xff0c;使用容器可以通过id值获取对应的bean&#xff0c;在一个容器中id值唯一 class&#xff1a; bean的类型&#xff0c;即配置的bean的全路径类名 <bean id"bookDao" class "com.zhang…

Java八股文(MyBatis Plus)

Java八股文のMyBatis Plus MyBatis Plus MyBatis Plus MyBatis Plus 是什么&#xff1f;它与 MyBatis 有什么区别&#xff1f; MyBatis Plus 是基于 MyBatis 进行扩展的一款持久层框架&#xff0c;它提供了一系列增强功能&#xff0c;简化了 MyBatis 的使用。 与 MyBatis 相比…

(十八)【Jmeter】取样器(Sampler)之BeanShell 取样器

简述 操作路径如下: 作用:通过Beanshell脚本来编写自定义请求。配置:编写Beanshell脚本代码,实现请求逻辑。使用场景:在JMeter中利用Beanshell脚本语言的特性进行自定义请求。优点:可以利用Beanshell脚本语言的丰富功能。缺点:脚本语言的性能可能不如其他编译语言,且…

论文阅读——SpectralGPT

SpectralGPT: Spectral Foundation Model SpectralGPT的通用RS基础模型&#xff0c;该模型专门用于使用新型3D生成预训练Transformer&#xff08;GPT&#xff09;处理光谱RS图像。 重建损失由两个部分组成&#xff1a;令牌到令牌和频谱到频谱 下游任务&#xff1a;

Linux进程管理:(六)SMP负载均衡

文章说明&#xff1a; Linux内核版本&#xff1a;5.0 架构&#xff1a;ARM64 参考资料及图片来源&#xff1a;《奔跑吧Linux内核》 Linux 5.0内核源码注释仓库地址&#xff1a; zhangzihengya/LinuxSourceCode_v5.0_study (github.com) 1. 前置知识 1.1 CPU管理位图 内核…

使用Java Runtime执行docker下的mysqldump

Runtime直接使用 docker exec mysql mysqldump -u%s -p%s cblog > %s&#xff08;%s是需要填充的数据&#xff09;&#xff0c;命令无法执行并且不会报错&#xff0c;需要使用字符串数组加入"sh", “-c”&#xff0c;具体代码示例&#xff1a; /*** MySQL数据备份…

无线局域网——wlan

目录 一.wlan的含义和发展 二.wlan技术带来的挑战 1.企业办公场景多样 2.位置速度的要求 3.安全的要求 4.规范的挑战 三.家庭和企业不同的部署需求 1.胖AP模式组网 2.AC瘦AP模式组网 3.组网模式的不同 四.三层隧道转发实验 1.拓扑 2.AP上线 核心交换机vlan ​编辑…

Magical Combat VFX

这个包包含30个可供游戏使用的VFX,有各种口味,为您的游戏增添趣味! 所有VFX都经过了很好的优化,可以在所有平台上使用。 这个包特别有一堆闪电魔法,有两种主要的变体,一种是深色的,另一种是浅色的。但它也提供了一系列其他视觉效果,如神圣咒语、音乐主题等等! 我们提供…

解决谷歌浏览器最新chrome94版本CORS跨域问题

项目场景&#xff1a; 谷歌浏览器升级到chrome94版本出现CORS跨域问题 问题描述 解决谷歌浏览器最新chrome94版本CORS跨域问题。 CORS跨域问题&#xff1a; 升级谷歌浏览器最新chrome94版本后&#xff0c;提示Access to XMLHttpRequest at ‘http://localhost:xxxx/api’ fro…

uni-app发布 h5 与ASP .NET MVC 后台 发布 到 IIS的同一端口 并配置跨域

iis 安装URL重写 选择对应的后台项目&#xff0c;进行url重写 编辑【模式】部分的内容的重写规则&#xff0c;我这里是h5中请求的前缀是api&#xff0c;大家可以根据自己的前缀进行修改。 编写【操作类型】为重写&#xff0c;并写重写url&#xff0c;按照图中设置即可。 uni…

使用Python构建RESTful API的最佳实践【第137篇—RESTful API】

&#x1f47d;发现宝藏 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。【点击进入巨牛的人工智能学习网站】。 使用Python构建RESTful API的最佳实践 在当今的软件开发中&#xff0c;构建RESTful API已经…

【系统性】 循序渐进学C++

循序渐进学C 第一阶段&#xff1a;基础 一、环境配置 1.1.第一个程序&#xff08;基本格式&#xff09; ​ #include <iosteam> using namespace std;int main(){cout<<"hello world"<<endl;system("pause"); }​ 模板 #include &…

【开源鸿蒙】编译OpenHarmony轻量系统QEMU RISC-V版

文章目录 一、背景介绍二、准备OpenHarmony源代码三、准备hb命令3.1 安装hb命令3.2 检查hb命令 四、编译RISC-V架构的OpenHarmony轻量系统4.1 设置hb构建目标4.2 启动hb构建过程 五、问题解决5.1 hb set 报错问题解决 六、参考链接 开源鸿蒙坚果派&#xff0c;学习鸿蒙一起来&a…

【开源】SpringBoot框架开发二手车交易系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 二手车档案管理模块2.3 车辆预约管理模块2.4 车辆预定管理模块2.5 车辆留言板管理模块2.6 车辆资讯管理模块 三、系统设计3.1 E-R图设计3.2 可行性分析3.2.1 技术可行性分析3.2.2 操作可行性3.2.3 经济…

HarmonyOS NEXT应用开发—发布图片评论

介绍 本示例将通过发布图片评论场景&#xff0c;介绍如何使用startAbilityForResult接口拉起相机拍照&#xff0c;并获取相机返回的数据。 效果图预览 使用说明 通过startAbilityForResult接口拉起相机&#xff0c;拍照后获取图片地址。 实现思路 创建CommentData类&#…

vue ui 无反应解决方法

cmd 输入vue ui 无反应解决方法 在学习vuex的过程中&#xff0c;需要用到vue ui 建立项目&#xff0c;遇到的问题记录一下&#xff0c;希望能够以帮助有问题的其他人 查看vue版本 vue --version 或者 vue -V 发现vue版本才2.9.6 由于vue ui 命令需要vue3.0以上&#xff0c;…

如何实现图片上传至服务器

在绝大多数的项目中都会涉及到文件上传等&#xff0c;下面我们来说一下技术派中是如何实现原生图片上传的&#xff0c;这个功能说起来简单&#xff0c;但其实对于技术还是有考验的。图片的上传涉及到IO读写&#xff0c;一个文件上传的功能&#xff0c;就可以把IO流涉及到的知识…