Google 出品,Dart语言,Flutter Engine引擎,响应式设计模式,原生渲染。react
Flutter 是谷歌2018年发布的跨平台移动UI框架。与 react native 经过 Javascript 开发不一样,Flutter 的编程语言是Dart,因此执行时并不须要 Javascript 引擎,但实际效果最终也经过原生渲染。web
其余框架只是作了OEM封装,Flutter能够直接操做Skia进行绘制。 算法
从该架构图可知,Flutter框架可分为Framework层和Engine层;编程
框架(Framework)部分是用Dart语言写的,也是本系列文章主要涉及的部分。canvas
引擎(Engine)部分是用C++实现的。引擎为框架提供支撑,也是链接框架和系统(Android/iOS)的桥梁。设计模式
Flutter Framework: 整个框架层都是用Dart语言实现,该层提供一套基础库, 用于处理动画、绘图和手势等。而且基于绘图封装了一套 UI组件库,而且细分为两种风格的组件 。浏览器
Foundation、Animation、Painting、Gestures 为 Dart 实现的 UI 层,提供动画、手势及绘制。markdown
Rendering 渲染层,依赖 UI 层,在运行时 Rendering 层会构建一个 Widget 树,当有变化时,会根据必定的算法计算出有变化的部分,而后更新 Widget 树。数据结构
Widgets 层是 Flutter 提供的的一套基础组件库,在基础组件库之上,Flutter 还提供了 Material 和 Cupertino 两种视觉风格的组件库。架构
Materail : Android风格的Widget
Cupertino: IOS风格的Widget
Flutter Engine
Skia 是一个开源的二维图形库,提供各类经常使用的 API,并可在多种软硬件平台上运行。谷歌 Chrome 浏览器、Chrome OS、安卓、火狐浏览器、火狐操做系统以及其它许多产品都使用它做为图形引擎。
Skia 由谷歌出资管理,任何人均可基于 BSD 免费软件许可证使用 Skia。Skia 开发团队致力于开发其核心部分, 并普遍采纳各方对于 Skia 的开源贡献。
由于没有使用原生的 UI 和绘制框架,因此才保证了 Flutter 的高性能体验。
Flutter Engine: 这是一个纯 C++实现的 SDK,其中囊括了 Skia引擎、Dart运行时、文字排版引擎等。不过说白了,它就是 Dart的一个运行时,它能够以 JIT、JIT Snapshot 或者 AOT的模式运行 Dart代码。在代码调用 dart:ui库时,提供 dart:ui库中 Native Binding 实现。 不过别忘了,这个运行时还控制着 VSync信号的传递、GPU数据的填充等,而且还负责把客户端的事件传递到运行时中的代码。
…/sdk/flutter/packages/flutter/lib
Dart可以使用Dart2Js编译器把Dart代码编译成Js代码。大多数原生App元素可以经过DOM实现,DOM实现不了的元素能够经过Canvas来实现。
得益于 Engine 层,Flutter 甚至不使用移动平台的原生控件, 而是使用本身 Engine 来绘制 Widget (Flutter的显示单元),而 Dart 代码都是经过 AOT 编译为平台的原生代码,因此 Flutter 能够 直接与平台通讯,不须要JS引擎的桥接。同时 Flutter 惟一要求系统提供的是 canvas,以实现UI的绘制。
对于Android平台,Flutter引擎的C/C++代码是由NDK编译,在iOS平台,则是由LLVM编译,两个平台的Dart代码都是AOT编译为本地代码,Flutter应用程序使用本机指令集运行。Flutter正是是经过使用相同的渲染器、框架和一组widget,来同时构建iOS和Android应用,而无需维护两套独立的代码库。
经过platform channels 和本地进行通讯。
经过MethodChannel,Native也能调用Flutter的方法,这是一个双向的通道。
Android显示器运行在60帧/秒左右,一帧大概16.6ms。
绘制间隔时间大于16ms会出现卡顿现象。
在Flutter框架中存在着一个渲染流水线(Rendering pipline)。这个渲染流水线是由垂直同步信号(Vsync)驱动的,而Vsync信号是由系统提供的,若是你的Flutter app是运行在Android上的话,那Vsync信号就是咱们熟悉的Android的那个Vsync信号。
当Vsync信号到来之后,Flutter 框架会按照图里的顺序执行一系列动做: 动画(Animate)、构建(Build)、布局(Layout)和绘制(Paint),最终生成一个场景(Scene)以后送往底层,由GPU绘制到屏幕上。
动画(Animate)阶段:由于动画会随每一个Vsync信号的到来而改变状态(State),因此动画阶段是流水线的第一个阶段。
构建(Build)在这个阶段Flutter,在这个阶段那些须要被从新构建的Widget会在此时被从新构建。也就是咱们熟悉的StatelessWidget.build()或者State.build()被调用的时候。
布局(Layout)阶段,这时会肯定各个显示元素的位置,尺寸。此时是RenderObject.performLayout()被调用的时候。
绘制(Paint)阶段,此时是RenderObject.paint()被调用的时候。
以上是整个渲染流水线的一个大体的工做过程。
Flutter app只有在状态发生变化的时候须要触发渲染流水线。当你的app什么都不作的时候是不须要从新渲染页面的。因此,Vsync信号须要Flutter app去调度。好比咱们都知道若是你的某个页面须要发生变化的时候有可能会调用State.setState(),这个调用Flutter框架最终会发起一个调度Vsync信号的请求给底层。而后底层会在Vsync信号到来的时候驱动渲染流水线开始运做,最后把新的页面显示到屏幕上。
![]() |
Flutter框架渲染机制的一个示意图。
整个渲染流水线是运行在UI线程里的,以Vsync信号为驱动,在框架渲染完成以后会输出layer tree。
layer tree被送入engine,engine会把layer tree调度到GPU线程,在GPU线程内合成(compsite)layer tree,而后由Skia 2D渲染引擎渲染后送入GPU显示。
这里提到layer tree是由于咱们即将要分析的渲染流水线绘制阶段最终输出就是这样的layer tree。
因此绘制阶段并非简单的调用paint()函数这么简单了,而是不少地方都涉及到layer tree的管理。
Flutter只关心向 GPU提供视图数据,GPU的 VSync信号同步到 UI线程,UI线程使用 Dart来构建抽象的视图结构,这份数据结构在 GPU线程进行图层合成,视图数据提供给 Skia引擎渲染为 GPU数据,这些数据经过 OpenGL或者 Vulkan提供给 GPU。
![]() |
在Flutter中,大多数东西都是widget,而Widget是不可变的,仅支持一帧,而且在每一帧上不会直接更新,要更新而必须使用Widget的状态。无状态和有状态 widget 的核心特性是相同的,每一帧它们都会从新构建,有一个State对象,它能够跨帧存储状态数据并恢复它。 Flutter 上 Android 自带了 Skia,Skia是一个 2D的绘图引擎库,跨平台,因此能够被嵌入到 Flutter的 iOS SDK中,也使得 Flutter Android SDK要比 iOS SDK小不少。
一个 StatelessWidget 是不能被改变的,好比:Icon、Text等。
若是你的控件一旦显示,就不须要再作任何的变动,那么你应该使用 StatelessWidget。
一个 StatefulWidget 是有状态的,可变的。
它能够改变本身的外观,以响应用户的操做或者数据的变化。
好比:CheckBox、Switch..
![]() |